From f915aff074bff3ba3878232e60a34def56a4fb8a Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Thu, 15 May 2025 17:12:44 -0400 Subject: [PATCH 01/12] Begin Package Collections docs migration --- Documentation/PackageCollections.md | 384 +++++++++--------- .../PackageCollectionAdd.md | 143 +++++++ .../PackageCollectionSigned.md | 164 ++++++++ .../SwiftPackageCollections.md | 28 ++ .../Documentation.docc/SwiftPackageManager.md | 1 + 5 files changed, 528 insertions(+), 192 deletions(-) create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSigned.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollections.md diff --git a/Documentation/PackageCollections.md b/Documentation/PackageCollections.md index 4aef95e4a37..d0c5037add5 100644 --- a/Documentation/PackageCollections.md +++ b/Documentation/PackageCollections.md @@ -27,106 +27,106 @@ and can be published to the web or distributed to local file systems. - [Signing package collections](#package-collection-signing-optional) - [Protecting package collections](#protecting-package-collections) -## Using package collections - -With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package -collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). - -`swift package-collection` has the following subcommands: -- [`add`](#add-subcommand): Add a new collection -- [`describe`](#describe-subcommand): Get metadata for a collection or a package included in an imported collection -- [`list`](#list-subcommand): List configured collections -- [`refresh`](#refresh-subcommand): Refresh configured collections -- [`remove`](#remove-subcommand): Remove a configured collection -- [`search`](#search-subcommand): Search for packages by keywords or module names within imported collections - -### `add` subcommand - -This subcommand adds a package collection hosted on the web (HTTPS required): - -```bash -$ swift package-collection add https://www.example.com/packages.json -Added "Sample Package Collection" to your package collections. -``` - -Or found in the local file system: - -```bash -$ swift package-collection add file:///absolute/path/to/packages.json -Added "Sample Package Collection" to your package collections. -``` - -The optional `order` hint can be used to order collections and may potentially influence ranking in search results: - -```bash -$ swift package-collection add https://www.example.com/packages.json [--order N] -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](#requirements-on-signing-certificate). - -```bash -$ swift package-collection add https://www.example.com/bad-packages.json -The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. -``` - -Users may continue adding the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: - -```bash -$ 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](#protecting-package-collections). If a package collection is -expected to be signed but it isn't, user will see the following error message: - -```bash -$ swift package-collection add https://www.example.com/bad-packages.json -The collection is missing required signature, which means it might have been compromised. -``` - -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. - -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](#protecting-package-collections). 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: - -```bash -$ swift package-collection add https://www.example.com/packages.json -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. - -#### Unsigned package collections - -Users will get an error when trying to add an unsigned package collection: - -```bash -$ 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: - -```bash -$ swift package-collection add https://www.example.com/packages.json --trust-unsigned -``` - -The `--skip-signature-check` flag has no effects on unsigned collections. - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ### `describe` subcommand This subcommand shows metadata for a collection or a package included in an imported collection. The result can optionally be returned as JSON using `--json` for @@ -280,95 +280,95 @@ intended for package collection publishers: All package collections must adhere to the [collection data format](../Sources/PackageCollectionsModel/Formats/v1.md) 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](../Sources/PackageCollectionsModel). -### Package collection signing (optional) - -Package collections can be signed to establish authenticity and protect their integrity. Doing this is optional. Users will be prompted for confirmation before they can add an [unsigned collection](#unsigned-package-collections). - -[`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 - -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](#signed-package-collections) 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](#trusted-root-certificates). - -#### 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](#protecting-package-collections), otherwise the [signature check](#signed-package-collections) 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 - -[Signing](#package-collection-signing-optional) 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](#unsigned-package-collections) 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](#signed-package-collections). - -To defend against these attacks, SwiftPM 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". - -The process for collection publishers to define their certificate-pinning configuration is as follows: -1. Edit [`PackageCollectionSourceCertificatePolicy`](../Sources/PackageCollections/PackageCollections+CertificatePolicy.swift) and add an entry to the `defaultSourceCertPolicies` dictionary: - -```swift -private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] = [ - // The key should be the "host" component of the package collection URL. - // This would require all package collections hosted on this domain to be signed. - "www.example.com": CertificatePolicyConfig( - // The signing certificate must have this subject user ID - certPolicyKey: CertificatePolicyKey.default(subjectUserID: "exampleUserID"), - /* - To compute base64-encoded string of a certificate: - let certificateURL = URL(fileURLWithPath: ) - let certificateData = try Data(contentsOf: certificateURL) - let base64EncoodedCertificate = certificateData.base64EncodedString() - */ - base64EncodedRootCerts: [""] - ) -] -``` - -2. Open a pull request for review. The requestor must be able to provide proof of their identity and ownership on the domain: - - The requestor must provide the actual certificate files (DER-encoded). The SwiftPM team will verify that the certificate chain is valid and the values provided in the PR are correct. - - The requestor must add a TXT record referencing the pull request. The SwiftPM team will run `dig -t txt ` to verify. This would act as proof of domain ownership. -3. After the changes are accepted, they will take effect in the next SwiftPM release. - -Since certificate-pinning configuration is associated with web domains, it can only be applied to signed collections hosted on the web (i.e., URL begins with `https://`) and does -not cover those found on local file system (i.e., URL begins with `file://`). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md index c8082f18e5c..b10bd100200 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md @@ -4,12 +4,155 @@ @PageImage(purpose: icon, source: command-icon) } +## Overview + +This subcommand adds a package collection hosted on the web (HTTPS required): + +```bash +$ swift package-collection add https://www.example.com/packages.json +Added "Sample Package Collection" to your package collections. +``` + +Or found in the local file system: + +```bash +$ swift package-collection add file:///absolute/path/to/packages.json +Added "Sample Package Collection" to your package collections. +``` + +The optional `order` hint can be used to order collections and may potentially influence ranking in search results: + +```bash +$ swift package-collection add https://www.example.com/packages.json [--order N] +Added "Sample Package Collection" to your package collections. +``` + +## Usage + Add a new collection. ``` package-collection add [--order=] [--trust-unsigned] [--skip-signature-check] [--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=] [--experimental-explicit-module-build] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--version] [--help] ``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +## Command Options + - term **collection-url:** *URL of the collection to add.* diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSigned.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSigned.md new file mode 100644 index 00000000000..db8f7cd8bff --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSigned.md @@ -0,0 +1,164 @@ +# Signing + +Package collection publishers may sign a collection to protect its contents from being tampered with. + +## Overview + +Package collections can be signed to establish authenticity and protect their integrity. +Doing this is optional. +Users will be prompted 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 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 + +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](#signed-package-collections) 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](#trusted-root-certificates). + + +### Signed package collections + +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](). + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. +``` + +Users may continue adding the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: + +```bash +$ 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: + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection is missing required signature, which means it might have been compromised. +``` + +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. + +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: + +```bash +$ swift package-collection add https://www.example.com/packages.json +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. + +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. + + +#### 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. + +### Protecting package collections + +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. +- **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: +- Require signature check on their collections — this defends against "signature stripping". +- Restrict what certificate can be used for signing — this defends against "signature replacement". + +The process for collection publishers to define their certificate-pinning configuration is as follows: +1. Edit [`PackageCollectionSourceCertificatePolicy`](../Sources/PackageCollections/PackageCollections+CertificatePolicy.swift) and add an entry to the `defaultSourceCertPolicies` dictionary: + +```swift +private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] = [ + // The key should be the "host" component of the package collection URL. + // This would require all package collections hosted on this domain to be signed. + "www.example.com": CertificatePolicyConfig( + // The signing certificate must have this subject user ID + certPolicyKey: CertificatePolicyKey.default(subjectUserID: "exampleUserID"), + /* + To compute base64-encoded string of a certificate: + let certificateURL = URL(fileURLWithPath: ) + let certificateData = try Data(contentsOf: certificateURL) + let base64EncoodedCertificate = certificateData.base64EncodedString() + */ + base64EncodedRootCerts: [""] + ) +] +``` + +2. Open a pull request for review. The requestor must be able to provide proof of their identity and ownership on the domain: + - The requestor must provide the actual certificate files (DER-encoded). The SwiftPM team will verify that the certificate chain is valid and the values provided in the PR are correct. + - The requestor must add a TXT record referencing the pull request. The SwiftPM team will run `dig -t txt ` to verify. This would act as proof of domain ownership. +3. After the changes are accepted, they will take effect in the next SwiftPM release. + +Since certificate-pinning configuration is associated with web domains, it can only be applied to signed collections hosted on the web (i.e., URL begins with `https://`) and does +not cover those found on local file system (i.e., URL begins with `file://`). + +## Unsigned package collections + +Users will get an error when trying to add an unsigned package collection: + +```bash +$ 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: + +```bash +$ swift package-collection add https://www.example.com/packages.json --trust-unsigned +``` + +The `--skip-signature-check` flag has no effects on unsigned collections. + diff --git a/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollections.md new file mode 100644 index 00000000000..8444592c721 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollections.md @@ -0,0 +1,28 @@ +# Package Collections + +Learn to create 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 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. + +## Using package collections + +With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package +collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). + +`swift package-collection` has the following subcommands: +- [`add`](): Add a new collection +- [`describe`](#describe-subcommand): Get metadata for a collection or a package included in an imported collection +- [`list`](#list-subcommand): List configured collections +- [`refresh`](#refresh-subcommand): Refresh configured collections +- [`remove`](#remove-subcommand): Remove a configured collection +- [`search`](#search-subcommand): Search for packages by keywords or module names within imported collections + +## Topics + +- [`Signed Package Collections`]() +- [`Unsigned package collections`]() diff --git a/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageManager.md b/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageManager.md index d6df794d206..8834925c2f0 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageManager.md +++ b/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageManager.md @@ -16,6 +16,7 @@ The Swift Package Manager leets you share your code as a package, depend on and - - +- From 85dd8fe496772a4b67faae7d76c986d0ff5ca1c6 Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Tue, 20 May 2025 15:03:47 -0400 Subject: [PATCH 02/12] Update package collection CLI subcommand summaries - add more information to the subcommand pages, giving a brief overview before describing the usage of the command itself - update the links to these subcomand pages for the package collection guide --- Documentation/PackageCollections.md | 384 +++++++++--------- .../Documentation.docc/Documentation.md | 2 +- ...geCollections.md => PackageCollections.md} | 14 +- .../PackageCollectionAdd.md | 122 +----- .../PackageCollectionDescribe.md | 7 + .../PackageCollectionList.md | 14 + .../PackageCollectionRefresh.md | 14 + .../PackageCollectionRemove.md | 11 + .../PackageCollectionSearch.md | 7 + .../SwiftPackageCollectionCommands.md | 2 +- 10 files changed, 257 insertions(+), 320 deletions(-) rename Sources/PackageManagerDocs/Documentation.docc/{SwiftPackageCollections.md => PackageCollections.md} (62%) diff --git a/Documentation/PackageCollections.md b/Documentation/PackageCollections.md index d0c5037add5..4aef95e4a37 100644 --- a/Documentation/PackageCollections.md +++ b/Documentation/PackageCollections.md @@ -27,106 +27,106 @@ and can be published to the web or distributed to local file systems. - [Signing package collections](#package-collection-signing-optional) - [Protecting package collections](#protecting-package-collections) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +## Using package collections + +With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package +collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). + +`swift package-collection` has the following subcommands: +- [`add`](#add-subcommand): Add a new collection +- [`describe`](#describe-subcommand): Get metadata for a collection or a package included in an imported collection +- [`list`](#list-subcommand): List configured collections +- [`refresh`](#refresh-subcommand): Refresh configured collections +- [`remove`](#remove-subcommand): Remove a configured collection +- [`search`](#search-subcommand): Search for packages by keywords or module names within imported collections + +### `add` subcommand + +This subcommand adds a package collection hosted on the web (HTTPS required): + +```bash +$ swift package-collection add https://www.example.com/packages.json +Added "Sample Package Collection" to your package collections. +``` + +Or found in the local file system: + +```bash +$ swift package-collection add file:///absolute/path/to/packages.json +Added "Sample Package Collection" to your package collections. +``` + +The optional `order` hint can be used to order collections and may potentially influence ranking in search results: + +```bash +$ swift package-collection add https://www.example.com/packages.json [--order N] +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](#requirements-on-signing-certificate). + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. +``` + +Users may continue adding the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: + +```bash +$ 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](#protecting-package-collections). If a package collection is +expected to be signed but it isn't, user will see the following error message: + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection is missing required signature, which means it might have been compromised. +``` + +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. + +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](#protecting-package-collections). 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: + +```bash +$ swift package-collection add https://www.example.com/packages.json +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. + +#### Unsigned package collections + +Users will get an error when trying to add an unsigned package collection: + +```bash +$ 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: + +```bash +$ swift package-collection add https://www.example.com/packages.json --trust-unsigned +``` + +The `--skip-signature-check` flag has no effects on unsigned collections. + ### `describe` subcommand This subcommand shows metadata for a collection or a package included in an imported collection. The result can optionally be returned as JSON using `--json` for @@ -280,95 +280,95 @@ intended for package collection publishers: All package collections must adhere to the [collection data format](../Sources/PackageCollectionsModel/Formats/v1.md) 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](../Sources/PackageCollectionsModel). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +### Package collection signing (optional) + +Package collections can be signed to establish authenticity and protect their integrity. Doing this is optional. Users will be prompted for confirmation before they can add an [unsigned collection](#unsigned-package-collections). + +[`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 + +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](#signed-package-collections) 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](#trusted-root-certificates). + +#### 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](#protecting-package-collections), otherwise the [signature check](#signed-package-collections) 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 + +[Signing](#package-collection-signing-optional) 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](#unsigned-package-collections) 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](#signed-package-collections). + +To defend against these attacks, SwiftPM 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". + +The process for collection publishers to define their certificate-pinning configuration is as follows: +1. Edit [`PackageCollectionSourceCertificatePolicy`](../Sources/PackageCollections/PackageCollections+CertificatePolicy.swift) and add an entry to the `defaultSourceCertPolicies` dictionary: + +```swift +private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] = [ + // The key should be the "host" component of the package collection URL. + // This would require all package collections hosted on this domain to be signed. + "www.example.com": CertificatePolicyConfig( + // The signing certificate must have this subject user ID + certPolicyKey: CertificatePolicyKey.default(subjectUserID: "exampleUserID"), + /* + To compute base64-encoded string of a certificate: + let certificateURL = URL(fileURLWithPath: ) + let certificateData = try Data(contentsOf: certificateURL) + let base64EncoodedCertificate = certificateData.base64EncodedString() + */ + base64EncodedRootCerts: [""] + ) +] +``` + +2. Open a pull request for review. The requestor must be able to provide proof of their identity and ownership on the domain: + - The requestor must provide the actual certificate files (DER-encoded). The SwiftPM team will verify that the certificate chain is valid and the values provided in the PR are correct. + - The requestor must add a TXT record referencing the pull request. The SwiftPM team will run `dig -t txt ` to verify. This would act as proof of domain ownership. +3. After the changes are accepted, they will take effect in the next SwiftPM release. + +Since certificate-pinning configuration is associated with web domains, it can only be applied to signed collections hosted on the web (i.e., URL begins with `https://`) and does +not cover those found on local file system (i.e., URL begins with `file://`). diff --git a/Sources/PackageManagerDocs/Documentation.docc/Documentation.md b/Sources/PackageManagerDocs/Documentation.docc/Documentation.md index f693ad8d88f..0bfd9785934 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/Documentation.md +++ b/Sources/PackageManagerDocs/Documentation.docc/Documentation.md @@ -16,7 +16,7 @@ The Swift Package Manager leets you share your code as a package, depend on and - - -- +- ### Guides diff --git a/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md similarity index 62% rename from Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollections.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 8444592c721..8178604ccfd 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -11,16 +11,18 @@ and can be published to the web or distributed to local file systems. ## Using package collections +### Command-line + With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package -collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). +collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). `swift package-collection` has the following subcommands: - [`add`](): Add a new collection -- [`describe`](#describe-subcommand): Get metadata for a collection or a package included in an imported collection -- [`list`](#list-subcommand): List configured collections -- [`refresh`](#refresh-subcommand): Refresh configured collections -- [`remove`](#remove-subcommand): Remove a configured collection -- [`search`](#search-subcommand): Search for packages by keywords or module names within imported collections +- [`describe`](): Get metadata for a collection or a package included in an imported collection +- [`list`](): List configured collections +- [`refresh`](): Refresh configured collections +- [`remove`](): Remove a configured collection +- [`search`](): Search for packages by keywords or module names within imported collections ## Topics diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md index 2934c7ceeec..86d36a97510 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md @@ -4,6 +4,8 @@ @PageImage(purpose: icon, source: command-icon) } +Add a new collection. + ## Overview This subcommand adds a package collection hosted on the web (HTTPS required): @@ -29,130 +31,10 @@ Added "Sample Package Collection" to your package collections. ## Usage -Add a new collection. - ``` package-collection add [--order=] [--trust-unsigned] [--skip-signature-check] [--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=] [--experimental-explicit-module-build] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--version] [--help] ``` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Command Options - - term **collection-url**: *URL of the collection to add.* diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md index ee561284fde..4f449d40fbb 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md @@ -6,6 +6,13 @@ Get metadata for a collection or a package included in an imported collection. +## Overview + +This subcommand shows metadata for a collection or a package included in an imported collection. The result can optionally be returned as JSON using `--json` for +integration into other tools. + +## Usage + ``` package-collection describe [--json] [--version=] [--skip-signature-check] [--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=] [--experimental-explicit-module-build] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionList.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionList.md index 6fad653882a..f135aa98ed7 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionList.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionList.md @@ -6,6 +6,20 @@ List configured collections. +## Overview + +This subcommand lists all collections that are configured by the user: + +```bash +$ swift package-collection list [--json] +Sample Package Collection - https://example.com/packages.json +... +``` + +The result can optionally be returned as JSON using `--json` for integration into other tools. + +## Usage + ``` package-collection list [--json] [--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=] [--experimental-explicit-module-build] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRefresh.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRefresh.md index eb51cfbef9c..04ea448af1c 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRefresh.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRefresh.md @@ -6,6 +6,20 @@ Refresh configured collections. +## Overview + +This subcommand refreshes any cached data manually: + +```bash +$ swift package-collection refresh +Refreshed 5 configured package collections. +``` + +SwiftPM will also automatically refresh data under various conditions, but some queries such as search will rely on locally cached data. + + +## Usage + ``` package-collection refresh [--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=] [--experimental-explicit-module-build] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRemove.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRemove.md index 6324856c04c..fbb20640eae 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRemove.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionRemove.md @@ -6,6 +6,17 @@ Remove a configured collection. +## Overview + +This subcommand removes a collection from the user's list of configured collections: + +```bash +$ swift package-collection remove https://www.example.com/packages.json +Removed "Sample Package Collection" from your package collections. +``` + +## Usage + ``` package-collection remove [--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=] [--experimental-explicit-module-build] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md index a625d984f43..a869a20bff0 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md @@ -6,6 +6,13 @@ Search for packages by keywords or module names. +## Overview + +This subcommand searches for packages by keywords or module names within imported collections. The result can optionally be returned as JSON using `--json` for +integration into other tools. + +## Usage + ``` package-collection search [--json] --keywords|module [--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=] [--experimental-explicit-module-build] [--build-system=] [--=] [--enable-dead-strip|disable-dead-strip] [--disable-local-rpath] [--version] [--help] ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollectionCommands.md b/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollectionCommands.md index ebcb37c7beb..6b00bf37325 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollectionCommands.md +++ b/Sources/PackageManagerDocs/Documentation.docc/SwiftPackageCollectionCommands.md @@ -14,7 +14,7 @@ Overview of package manager commands here... ## Topics -### Adding a package colleciton +### Adding a package collection - ### Finding package collections From 72754b40c68c01c9d3f2be72fbab65a8eefab26b Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Tue, 20 May 2025 16:39:05 -0400 Subject: [PATCH 03/12] Add the rest of the collections guide files - add a file per topic for package collections - link out to the subcommand reference when applicable --- .../PackageCollectionAddGuide.md | 92 +++++++++++++++ ...PackageCollectionConfigurationFileGuide.md | 11 ++ .../PackageCollectionDescribeGuide.md | 73 ++++++++++++ .../PackageCollectionListGuide.md | 13 +++ .../PackageCollectionPublishingGuide.md | 110 ++++++++++++++++++ .../PackageCollectionRefreshGuide.md | 13 +++ .../PackageCollectionRemoveGuide.md | 10 ++ .../PackageCollectionSearchGuide.md | 30 +++++ .../Documentation.docc/PackageCollections.md | 24 +++- ...nSigned.md => PackageCollectionSigning.md} | 0 .../PackageCollectionAddGuide.md | 11 ++ 11 files changed, 385 insertions(+), 2 deletions(-) create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionDescribeGuide.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md create mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md rename Sources/PackageManagerDocs/Documentation.docc/PackageCollections/{PackageCollectionSigned.md => PackageCollectionSigning.md} (100%) create mode 100644 Sources/PackageManagerDocs/PackageCollectionAddGuide.md diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md new file mode 100644 index 00000000000..c6e4de331e4 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md @@ -0,0 +1,92 @@ +# Add a package + +Learn how to add a package to your collection. + +## Overview + +This [subcommand]() adds a package collection hosted on the web (HTTPS required): + +```bash +$ swift package-collection add https://www.example.com/packages.json +Added "Sample Package Collection" to your package collections. +``` + +Or found in the local file system: + +```bash +$ swift package-collection add file:///absolute/path/to/packages.json +Added "Sample Package Collection" to your package collections. +``` + +The optional `order` hint can be used to order collections and may potentially influence ranking in search results: + +```bash +$ swift package-collection add https://www.example.com/packages.json [--order N] +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](). + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. +``` + +Users may continue adding the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: + +```bash +$ 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: + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection is missing required signature, which means it might have been compromised. +``` + +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. + +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: + +```bash +$ swift package-collection add https://www.example.com/packages.json +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. + +#### Unsigned package collections + +Users will get an error when trying to add an unsigned package collection: + +```bash +$ 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: + +```bash +$ swift package-collection add https://www.example.com/packages.json --trust-unsigned +``` + +The `--skip-signature-check` flag has no effects on unsigned collections. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md new file mode 100644 index 00000000000..c8543b32972 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md @@ -0,0 +1,11 @@ +# Configuration file + +Learn about how package collections are configured. + +## Overview + +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](#add-subcommand). + +This file is managed through SwiftPM commands and users are not expected to edit it by hand. + diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionDescribeGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionDescribeGuide.md new file mode 100644 index 00000000000..626a0131948 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionDescribeGuide.md @@ -0,0 +1,73 @@ +# Metadata of package collections + +Learn how to fetch metadata about your package collection. + +## Overview + +The [`describe` subcommand]() shows metadata for a collection or a package included in an imported collection. The result can optionally be returned as JSON using `--json` for +integration into other tools. + +### Metadata and packages of a collection + +`describe` can be used for both collections that have been previously added to the list of the user's configured collections, as well as to preview any other collections. + +```bash +$ swift package-collection describe [--json] https://www.example.com/packages.json +Name: Sample Package Collection +Source: https://www.example.com/packages.json +Description: ... +Keywords: best, packages +Created At: 2020-05-30 12:33 +Packages: + https://github.com/jpsim/yams + ... +``` + +#### Signed package collections + +If a collection is signed, SwiftPM will check that the signature is valid before showing a preview. + +```bash +$ swift package-collection describe https://www.example.com/bad-packages.json +The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. +``` + +Users may continue previewing the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: + +```bash +$ swift package-collection describe https://www.example.com/packages.json --skip-signature-check +``` + +### Metadata of a package + +`describe` can also show the metadata of a package included in an imported collection: + +```bash +$ swift package-collection describe [--json] https://github.com/jpsim/yams +Description: A sweet and swifty YAML parser built on LibYAML. +Available Versions: 4.0.0, 3.0.0, ... +Stars: 14 +Readme: https://github.com/jpsim/Yams/blob/master/README.md +Authors: @norio-nomura, @jpsim +-------------------------------------------------------------- +Latest Version: 4.0.0 +Package Name: Yams +Modules: Yams, CYaml +Supported Platforms: iOS, macOS, Linux, tvOS, watchOS +Supported Swift Versions: 5.3, 5.2, 5.1, 5.0 +License: MIT +``` + +### Metadata of a package version + +User may view additional metadata for a package version by passing `--version`: + +```bash +$ swift package-collection describe [--json] --version 4.0.0 https://github.com/jpsim/yams +Package Name: Yams +Version: 4.0.0 +Modules: Yams, CYaml +Supported Platforms: iOS, macOS, Linux, tvOS, watchOS +Supported Swift Versions: 5.3, 5.2, 5.1, 5.0 +License: MIT +``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md new file mode 100644 index 00000000000..e15c630e11b --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md @@ -0,0 +1,13 @@ +# Listing package collections + +## Overview + +List [`list` subcommand]() lists all collections that are configured by the user: + +```bash +$ swift package-collection list [--json] +Sample Package Collection - https://example.com/packages.json +... +``` + +The result can optionally be returned as JSON using `--json` for integration into other tools. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md new file mode 100644 index 00000000000..215eed7eb2e --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md @@ -0,0 +1,110 @@ +# Publishing package collections + +Learn how to publish package collections. + +## Overview + +Package collections can be created and published by anyone. The [swift-package-collection-generator](https://github.com/apple/swift-package-collection-generator) project provides tooling +intended for package collection publishers: +- [`package-collection-generate`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionGenerator): Generate a package collection given a list of package URLs +- [`package-collection-sign`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionSigner): Sign a package collection +- [`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 + +### Creating package collections + +All package collections must adhere to the [collection data format](../Sources/PackageCollectionsModel/Formats/v1.md) 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](../Sources/PackageCollectionsModel). + +### Package collection signing (optional) + +Package collections can be signed to establish authenticity and protect their integrity. Doing this is optional. Users will be prompted for confirmation before they can add an [unsigned collection](#unsigned-package-collections). + +[`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 + +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](#signed-package-collections) 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](#trusted-root-certificates). + +#### 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](#protecting-package-collections), otherwise the [signature check](#signed-package-collections) 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 + +[Signing](#package-collection-signing-optional) 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](#unsigned-package-collections) 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](#signed-package-collections). + +To defend against these attacks, SwiftPM 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". + +The process for collection publishers to define their certificate-pinning configuration is as follows: +1. Edit [`PackageCollectionSourceCertificatePolicy`](../Sources/PackageCollections/PackageCollections+CertificatePolicy.swift) and add an entry to the `defaultSourceCertPolicies` dictionary: + +```swift +private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] = [ + // The key should be the "host" component of the package collection URL. + // This would require all package collections hosted on this domain to be signed. + "www.example.com": CertificatePolicyConfig( + // The signing certificate must have this subject user ID + certPolicyKey: CertificatePolicyKey.default(subjectUserID: "exampleUserID"), + /* + To compute base64-encoded string of a certificate: + let certificateURL = URL(fileURLWithPath: ) + let certificateData = try Data(contentsOf: certificateURL) + let base64EncoodedCertificate = certificateData.base64EncodedString() + */ + base64EncodedRootCerts: [""] + ) +] +``` + +2. Open a pull request for review. The requestor must be able to provide proof of their identity and ownership on the domain: + - The requestor must provide the actual certificate files (DER-encoded). The SwiftPM team will verify that the certificate chain is valid and the values provided in the PR are correct. + - The requestor must add a TXT record referencing the pull request. The SwiftPM team will run `dig -t txt ` to verify. This would act as proof of domain ownership. +3. After the changes are accepted, they will take effect in the next SwiftPM release. + +Since certificate-pinning configuration is associated with web domains, it can only be applied to signed collections hosted on the web (i.e., URL begins with `https://`) and does +not cover those found on local file system (i.e., URL begins with `file://`). diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md new file mode 100644 index 00000000000..b21b50eded9 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md @@ -0,0 +1,13 @@ +# Refresh + +## Overview + +The [`refresh` subcommand]() refreshes any cached data manually: + +```bash +$ swift package-collection refresh +Refreshed 5 configured package collections. +``` + +SwiftPM will also automatically refresh data under various conditions, but some queries such as search will rely on locally cached data. + diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md new file mode 100644 index 00000000000..f315a6fdd3c --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md @@ -0,0 +1,10 @@ +# Removing a package + +## Overview + +This subcommand removes a collection from the user's list of configured collections: + +```bash +$ swift package-collection remove https://www.example.com/packages.json +Removed "Sample Package Collection" from your package collections. +``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md new file mode 100644 index 00000000000..157f5c24120 --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md @@ -0,0 +1,30 @@ +# Searching for a package + +## Overview + +The [`search` subcommand]() searches for packages by keywords or module names within imported collections. The result can optionally be returned as JSON using `--json` for +integration into other tools. + +### String-based search + +The search command does a string-based search when using the `--keywords` option and returns the list of packages that matches the query: + +```bash +$ swift package-collection search [--json] --keywords yaml +https://github.com/jpsim/yams: A sweet and swifty YAML parser built on LibYAML. +... +``` + +### Module-based search + +The search command does a search for a specific module name when using the `--module` option: + +```bash +$ swift package-collection search [--json] --module yams +Package Name: Yams +Latest Version: 4.0.0 +Description: A sweet and swifty YAML parser built on LibYAML. +-------------------------------------------------------------- +... +``` + diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 8178604ccfd..4f257db8077 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -26,5 +26,25 @@ collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). Summary + +## Overview + +Text + +### Section header + +Text From 2bce80ea83d16e05c96f86fd886ef66821cc3ffa Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Tue, 20 May 2025 16:43:14 -0400 Subject: [PATCH 04/12] Update titles and re-group collections topics --- .../Documentation.docc/PackageCollectionListGuide.md | 2 ++ .../PackageCollectionRefreshGuide.md | 2 ++ .../PackageCollectionRemoveGuide.md | 2 ++ .../PackageCollectionSearchGuide.md | 2 ++ .../Documentation.docc/PackageCollections.md | 12 +++--------- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md index e15c630e11b..6b002173ee2 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md @@ -1,5 +1,7 @@ # Listing package collections +Learn how to view configured collections. + ## Overview List [`list` subcommand]() lists all collections that are configured by the user: diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md index b21b50eded9..4dec717d7f7 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md @@ -1,5 +1,7 @@ # Refresh +Learn how to refresh package collections. + ## Overview The [`refresh` subcommand]() refreshes any cached data manually: diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md index f315a6fdd3c..9e11aec6e49 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md @@ -1,5 +1,7 @@ # Removing a package +Learn how to remove a package from a collection. + ## Overview This subcommand removes a collection from the user's list of configured collections: diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md index 157f5c24120..0f1505a1c50 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md @@ -1,5 +1,7 @@ # Searching for a package +Learn how to query for a package in collections. + ## Overview The [`search` subcommand]() searches for packages by keywords or module names within imported collections. The result can optionally be returned as JSON using `--json` for diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 4f257db8077..0dabe274ea7 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -30,21 +30,15 @@ collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). - -- ### Guides - +- diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md index c6e4de331e4..d02c9387e79 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md @@ -4,7 +4,7 @@ Learn how to add a package to your collection. ## Overview -This [subcommand]() adds a package collection hosted on the web (HTTPS required): +The [`add` subcommand]() adds a package collection hosted on the web (HTTPS required): ```bash $ swift package-collection add https://www.example.com/packages.json diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md index c8543b32972..29ae1121b59 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionConfigurationFileGuide.md @@ -5,7 +5,7 @@ Learn about how package collections are configured. ## Overview 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](#add-subcommand). +and preferences such as those set by the `--trust-unsigned` and `--skip-signature-check` flags in the [`package-collection add` command](). This file is managed through SwiftPM commands and users are not expected to edit it by hand. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionCreationGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionCreationGuide.md new file mode 100644 index 00000000000..5a8ffd3659a --- /dev/null +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionCreationGuide.md @@ -0,0 +1,261 @@ +# Creating a package collection + +Learn how to create a Swift package collection. + +## Overview + +A package collection is a JSON document that contains a list of packages and metadata per package. + +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). + +## 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](). + +This file is managed through SwiftPM commands and users are not expected to edit it by hand. + +## Input Format + +To begin, define the top-level metadata about the collection: + +* `name`: The name of the package collection, for display purposes only. +* `overview`: A description of the package collection. **Optional.** +* `keywords`: An array of keywords that the collection is associated with. **Optional.** +* `formatVersion`: The version of the format to which the collection conforms. Currently, `1.0` is the only allowed value. +* `revision`: The revision number of this package collection. **Optional.** +* `generatedAt`: The ISO 8601-formatted datetime string when the package collection was generated. +* `generatedBy`: The author of this package collection. **Optional.** + * `name`: The author name. +* `packages`: A non-empty array of package objects. + +## Add packages to 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.** +* `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.** +* `license`: The package's *current* license information. **Optional.** + * `url`: The URL of the license file. + * `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: + +* `version`: The semantic version string. +* `summary`: A description of the package version. **Optional.** +* `manifests`: A non-empty map of manifests by Swift tools version. The keys are (semantic) tools version (more on this below), while the values are: + * `toolsVersion`: The Swift tools version specified in the manifest. + * `packageName`: The name of the package. + * `targets`: An array of the package version's targets. + * `name`: The target name. + * `moduleName`: The module name if this target can be imported as a module. **Optional.** + * `products`: An array of the package version's products. + * `name`: The product name. + * `type`: The product type. This must have the same JSON representation as SwiftPM's `PackageModel.ProductType`. + * `target`: An array of the product’s targets. + * `minimumPlatformVersions`: An array of the package version’s supported platforms specified in `Package.swift`. **Optional.** + +```json +{ + "5.2": { + "toolsVersion": "5.2", + "packageName": "MyPackage", + "targets": [ + { + "name": "MyTarget", + "moduleName": "MyTarget" + } + ], + "products": [ + { + "name": "MyProduct", + "type": { + "library": ["automatic"] + }, + "targets": ["MyTarget"] + } + ], + "minimumPlatformVersions": [ + { + "name": "macOS", + "version": "10.15" + } + ] + } +} +``` + +* `defaultToolsVersion`: The Swift tools version of the default manifest. The `manifests` map must contain this in its keys. +* `verifiedCompatibility`: An array of compatible platforms and Swift versions that has been tested and verified for. Valid platform names include `macOS`, `iOS`, `tvOS`, `watchOS`, `Linux`, `Android`, and `Windows`. Swift version should be semantic version string and as specific as possible. **Optional.** + +```json +{ + "platform": { + "name": "macOS" + }, + "swiftVersion": "5.3.2" +} +``` + +* `license`: The package version's license. **Optional.** + * `url`: The URL of the license file. + * `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. + * `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. + * `organizationName`: The organization name of the signing certificate's subject. +* `createdAt`: The ISO 8601-formatted datetime string when the package version was created. **Optional.** + +## 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) . + +The keys of the `manifests` map are Swift tools (semantic) versions: +* For `Package.swift`, the tools version specified in `Package.swift` should be used. +* For version-specific manifests, the tools version specified in the filename should be used. For example, for `Package@swift-4.2.swift` it would be `4.2`. The tools version in the manifest must match that in the filename. + +## 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. + +# Example + +```json +{ + "name": "Sample Package Collection", + "overview": "This is a sample package collection listing made-up packages.", + "keywords": ["sample package collection"], + "formatVersion": "1.0", + "revision": 3, + "generatedAt": "2020-10-22T06:03:52Z", + "packages": [ + { + "url": "https://www.example.com/repos/RepoOne.git", + "summary": "Package One", + "readmeURL": "https://www.example.com/repos/RepoOne/README", + "license": { + "name": "Apache-2.0", + "url": "https://www.example.com/repos/RepoOne/LICENSE" + }, + "versions": [ + { + "version": "0.1.0", + "summary": "Fixed a few bugs", + "manifests": { + "5.1": { + "toolsVersion": "5.1", + "packageName": "PackageOne", + "targets": [ + { + "name": "Foo", + "moduleName": "Foo" + } + ], + "products": [ + { + "name": "Foo", + "type": { + "library": ["automatic"] + }, + "targets": ["Foo"] + } + ] + } + }, + "defaultToolsVersion": "5.1", + "verifiedCompatibility": [ + { + "platform": { "name": "macOS" }, + "swiftVersion": "5.1" + }, + { + "platform": { "name": "iOS" }, + "swiftVersion": "5.1" + }, + { + "platform": { "name": "Linux" }, + "swiftVersion": "5.1" + } + ], + "license": { + "name": "Apache-2.0", + "url": "https://www.example.com/repos/RepoOne/LICENSE" + }, + "createdAt": "2020-10-21T09:25:36Z" + } + ] + }, + { + "url": "https://www.example.com/repos/RepoTwo.git", + "summary": "Package Two", + "readmeURL": "https://www.example.com/repos/RepoTwo/README", + "versions": [ + { + "version": "2.1.0", + "manifests": { + "5.2": { + "toolsVersion": "5.2", + "packageName": "PackageTwo", + "targets": [ + { + "name": "Bar", + "moduleName": "Bar" + } + ], + "products": [ + { + "name": "Bar", + "type": { + "library": ["automatic"] + }, + "targets": ["Bar"] + } + ] + } + }, + "defaultToolsVersion": "5.2" + }, + { + "version": "1.8.3", + "manifests": { + "5.0": { + "toolsVersion": "5.0", + "packageName": "PackageTwo", + "targets": [ + { + "name": "Bar", + "moduleName": "Bar" + } + ], + "products": [ + { + "name": "Bar", + "type": { + "library": ["automatic"] + }, + "targets": ["Bar"] + } + ] + } + }, + "defaultToolsVersion": "5.0" + } + ] + } + ] +} +``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md index 215eed7eb2e..b8b13b56631 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md @@ -11,14 +11,15 @@ 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 + diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md index 4dec717d7f7..e342aa1c258 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md @@ -1,4 +1,4 @@ -# Refresh +# Refreshing package collections Learn how to refresh package collections. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md index 9e11aec6e49..6af002be004 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md @@ -4,7 +4,7 @@ Learn how to remove a package from a collection. ## Overview -This subcommand removes a collection from the user's list of configured collections: +The [`remove` subcommand]() removes a collection from the user's list of configured collections: ```bash $ swift package-collection remove https://www.example.com/packages.json diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 0dabe274ea7..35fa2c7abee 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -5,15 +5,22 @@ Learn to create 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 make discovery of existing packages easier. +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. -## Using package collections +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. -### Command-line +## Using package-collection CLI -With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package +With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. +Contents of imported package collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). `swift package-collection` has the following subcommands: @@ -26,9 +33,14 @@ collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). - +- + + + ### Modifying package collections - @@ -40,5 +52,3 @@ collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). of the package if published to 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.** @@ -112,7 +114,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 [documentation](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md#package-signing) 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. @@ -132,6 +134,14 @@ The keys of the `manifests` map are Swift tools (semantic) versions: [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. +## 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](). + +> Note: This file is managed through SwiftPM commands and users are not expected to edit it by hand. + # Example ```json diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md index b8b13b56631..f63f9855a19 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md @@ -10,103 +10,3 @@ intended for package collection publishers: - [`package-collection-sign`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionSigner): Sign a package collection - [`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 - - diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSigning.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSigning.md similarity index 60% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSigning.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSigning.md index 0de0199fba6..55e04575fad 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSigning.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSigning.md @@ -6,7 +6,7 @@ Package collection publishers may sign a collection to protect its contents from Package collections can be signed to establish authenticity and protect their integrity. Doing this is optional. -Users will be prompted for confirmation before they can add an [unsigned collection](). +Users will be prompted 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 one must provide: @@ -36,65 +36,11 @@ A signed package collection has an extra `signature` object: } ``` -- 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](#signed-package-collections) 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](#trusted-root-certificates). +- 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](). -### Signed package collections - -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](). - -```bash -$ swift package-collection add https://www.example.com/bad-packages.json -The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. -``` - -Users may continue adding the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: - -```bash -$ 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: - -```bash -$ swift package-collection add https://www.example.com/bad-packages.json -The collection is missing required signature, which means it might have been compromised. -``` - -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. - -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: - -```bash -$ swift package-collection add https://www.example.com/packages.json -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. - -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. - - -#### Requirements on signing certificate +### 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. @@ -105,9 +51,17 @@ Certificates used for signing package collections must meet the following requir Non-expired, non-revoked Swift Package Collection certificates from [developer.apple.com](https://developer.apple.com) satisfy all of the criteria above. -### Protecting package collections +#### 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. + -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 +## Protecting package collections + +[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. - **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](). @@ -144,21 +98,3 @@ private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] Since certificate-pinning configuration is associated with web domains, it can only be applied to signed collections hosted on the web (i.e., URL begins with `https://`) and does not cover those found on local file system (i.e., URL begins with `file://`). - -## Unsigned package collections - -Users will get an error when trying to add an unsigned package collection: - -```bash -$ 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: - -```bash -$ swift package-collection add https://www.example.com/packages.json --trust-unsigned -``` - -The `--skip-signature-check` flag has no effects on unsigned collections. - diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 35fa2c7abee..d8bb7988aa3 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -35,13 +35,9 @@ collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). -- + - - - - ### Modifying package collections - - From 4d95081efd0d997e3d982629792f6e3b9e05b4f4 Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Thu, 22 May 2025 15:19:01 -0400 Subject: [PATCH 07/12] Add directory for package collection guides and fix titles --- .../PackageCollectionPublishingGuide.md | 12 ------------ .../PackageCollectionAddGuide.md | 4 ++-- .../PackageCollectionCreationGuide.md | 0 .../PackageCollectionDescribeGuide.md | 4 ++-- .../PackageCollectionListGuide.md | 4 ++-- .../PackageCollectionRefreshGuide.md | 4 ++-- .../PackageCollectionRemoveGuide.md | 2 +- .../PackageCollectionSearchGuide.md | 4 ++-- .../PackageCollectionSigning.md | 6 +++--- .../PackageCollections.md | 9 ++++----- 10 files changed, 18 insertions(+), 31 deletions(-) delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionAddGuide.md (96%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionCreationGuide.md (100%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionDescribeGuide.md (96%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionListGuide.md (79%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionRefreshGuide.md (79%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionRemoveGuide.md (94%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionSearchGuide.md (90%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollectionSigning.md (96%) rename Sources/PackageManagerDocs/Documentation.docc/{ => PackageCollectionsGuide}/PackageCollections.md (93%) diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md deleted file mode 100644 index f63f9855a19..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionPublishingGuide.md +++ /dev/null @@ -1,12 +0,0 @@ -# Publishing package collections - -Learn how to publish package collections. - -## Overview - -Package collections can be created and published by anyone. The [swift-package-collection-generator](https://github.com/apple/swift-package-collection-generator) project provides tooling -intended for package collection publishers: -- [`package-collection-generate`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionGenerator): Generate a package collection given a list of package URLs -- [`package-collection-sign`](https://github.com/apple/swift-package-collection-generator/tree/main/Sources/PackageCollectionSigner): Sign a package collection -- [`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 diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md similarity index 96% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md index 2134707a60e..10cdbddcadd 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionAddGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md @@ -1,4 +1,4 @@ -# Add a package +# Adding Packages Learn how to add a package to your collection. @@ -27,7 +27,7 @@ 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. +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. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionCreationGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md similarity index 100% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionCreationGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionDescribeGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md similarity index 96% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionDescribeGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md index 626a0131948..932cd09f28b 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionDescribeGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md @@ -1,6 +1,6 @@ -# Metadata of package collections +# Showing Package Collection Metadata -Learn how to fetch metadata about your package collection. +Discover more about package collections and their packages. ## Overview diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md similarity index 79% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md index 6b002173ee2..a6cdbe4c9c2 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionListGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md @@ -1,6 +1,6 @@ -# Listing package collections +# Listing configured Package Collections -Learn how to view configured collections. +Discover user-configured Package Collections. ## Overview diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md similarity index 79% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md index e342aa1c258..316209524c1 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRefreshGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md @@ -1,6 +1,6 @@ -# Refreshing package collections +# Refreshing Package Collection Data -Learn how to refresh package collections. +Refresh the cached data for package collections. ## Overview diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md similarity index 94% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md index 6af002be004..55d617f92b0 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionRemoveGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md @@ -1,4 +1,4 @@ -# Removing a package +# Removing Packages Learn how to remove a package from a collection. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md similarity index 90% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md index 0f1505a1c50..40eae7fd260 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSearchGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md @@ -1,6 +1,6 @@ -# Searching for a package +# Querying for Packages in Package Collections -Learn how to query for a package in collections. +Find packages in a configured Package Collection. ## Overview diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSigning.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md similarity index 96% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSigning.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md index 55e04575fad..61d3a73172d 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionSigning.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md @@ -1,6 +1,6 @@ -# Protecting package collections +# Signing and Protecting Package Collections -Package collection publishers may sign a collection to protect its contents from being tampered with. +Learn how to protect and configure a signed Package Collection. ## Overview @@ -64,7 +64,7 @@ root certificate(s) that they use downloadable so that users can adjust their se [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. -- **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](). +- **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: - Require signature check on their collections — this defends against "signature stripping". diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollections.md similarity index 93% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollections.md index d8bb7988aa3..6bb59611a49 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollections.md @@ -17,7 +17,7 @@ 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. -## Using package-collection CLI +## Using the package-collection CLI With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package @@ -35,16 +35,15 @@ collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). - -### Modifying package collections +### Modifying Package Collections - - - -### Inspecting package collections +### Inspecting Package Collections - -- - +- From 4aa6e665f07e728fb9a82ed65b4f7ee7a524cda4 Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Thu, 22 May 2025 16:14:26 -0400 Subject: [PATCH 08/12] Edit titles of collections articles --- .../PackageCollectionsGuide/PackageCollectionAddGuide.md | 2 +- .../PackageCollectionsGuide/PackageCollectionCreationGuide.md | 2 +- .../PackageCollectionsGuide/PackageCollectionDescribeGuide.md | 2 +- .../PackageCollectionsGuide/PackageCollectionListGuide.md | 4 ++-- .../PackageCollectionsGuide/PackageCollectionRefreshGuide.md | 2 +- .../PackageCollectionsGuide/PackageCollectionRemoveGuide.md | 2 +- .../PackageCollectionsGuide/PackageCollectionSearchGuide.md | 2 +- .../PackageCollectionsGuide/PackageCollectionSigning.md | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md index 10cdbddcadd..94820b9872c 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md @@ -1,4 +1,4 @@ -# Adding Packages +# Adding packages Learn how to add a package to your collection. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md index a2fc01f02dd..380dfcedbe6 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md @@ -1,4 +1,4 @@ -# Creating and Publishing a Package Collection +# Creating and publishing package collections Learn how to create and publish a Swift package collection. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md index 932cd09f28b..24d3f3109b4 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md @@ -1,4 +1,4 @@ -# Showing Package Collection Metadata +# Showing package collection metadata Discover more about package collections and their packages. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md index a6cdbe4c9c2..11e4e13c1a6 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md @@ -1,6 +1,6 @@ -# Listing configured Package Collections +# List existing package collections -Discover user-configured Package Collections. +Discover user-configured package collections. ## Overview diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md index 316209524c1..bd373c4941e 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md @@ -1,4 +1,4 @@ -# Refreshing Package Collection Data +# Refreshing package collection data Refresh the cached data for package collections. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md index 55d617f92b0..0b6dc111e5d 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md @@ -1,4 +1,4 @@ -# Removing Packages +# Removing packages Learn how to remove a package from a collection. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md index 40eae7fd260..3d7edee1683 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md @@ -1,4 +1,4 @@ -# Querying for Packages in Package Collections +# Querying for packages in package collections Find packages in a configured Package Collection. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md index 61d3a73172d..cec31319fc6 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md @@ -1,6 +1,6 @@ -# Signing and Protecting Package Collections +# Signing and protecting package collections -Learn how to protect and configure a signed Package Collection. +Learn how to protect and configure a signed package collection. ## Overview From e0282319ff6b25c7f51e9b50218f0134b5ffd6bd Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Mon, 26 May 2025 12:36:54 -0400 Subject: [PATCH 09/12] Re-structure topics into single article, move overviews to CLI command pages --- ...CreationGuide.md => PackageCollections.md} | 158 ++++++++++++++++-- .../PackageCollectionAdd.md | 67 ++++++++ .../PackageCollectionDescribe.md | 65 +++++++ .../PackageCollectionSearch.md | 23 +++ .../PackageCollectionAddGuide.md | 92 ---------- .../PackageCollectionDescribeGuide.md | 73 -------- .../PackageCollectionListGuide.md | 15 -- .../PackageCollectionRefreshGuide.md | 15 -- .../PackageCollectionRemoveGuide.md | 12 -- .../PackageCollectionSearchGuide.md | 32 ---- .../PackageCollectionSigning.md | 100 ----------- .../PackageCollections.md | 49 ------ 12 files changed, 296 insertions(+), 405 deletions(-) rename Sources/PackageManagerDocs/Documentation.docc/{PackageCollectionsGuide/PackageCollectionCreationGuide.md => PackageCollections.md} (54%) delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md delete mode 100644 Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollections.md diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md similarity index 54% rename from Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md rename to Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 380dfcedbe6..eee23bb7159 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionCreationGuide.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -1,9 +1,38 @@ -# Creating and publishing package collections +# Package Collections -Learn how to create and publish a Swift package collection. +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. + +### Using the package-collection CLI + +With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. +Contents of imported package +collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). + +`swift package-collection` has the following subcommands: +- [`add`](): Add a new collection +- [`describe`](): Get metadata for a collection or a package included in an imported collection +- [`list`](): List configured collections +- [`refresh`](): Refresh configured collections +- [`remove`](): Remove a configured collection +- [`search`](): Search for packages by keywords or module names within imported collections + +### Creating Package Collections + A package collection is a JSON document that contains a list of packages and metadata per package. Package collections can be created and published by anyone. The [swift-package-collection-generator](https://github.com/apple/swift-package-collection-generator) project provides tooling @@ -13,13 +42,10 @@ 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 - -## Creating Package Collections - -All package collections must adhere to the [collection data format]() for SwiftPM to be able to consume them. The recommended way +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 +#### Input Format To begin, define the top-level metadata about the collection: @@ -33,7 +59,7 @@ To begin, define the top-level metadata about the collection: * `name`: The author name. * `packages`: A non-empty array of package objects. -## Add packages to the collection +### Add packages to the collection Each item in the `packages` array is a package object with the following properties: @@ -47,9 +73,9 @@ 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. +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 +### Add versions to a package A version object has metadata extracted from `Package.swift` and optionally additional metadata from other sources: @@ -121,7 +147,7 @@ A version object has metadata extracted from `Package.swift` and optionally addi * `organizationName`: The organization name of the signing certificate's subject. * `createdAt`: The ISO 8601-formatted datetime string when the package version was created. **Optional.** -## Version-specific manifests +### 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) . @@ -129,20 +155,20 @@ The keys of the `manifests` map are Swift tools (semantic) versions: * For `Package.swift`, the tools version specified in `Package.swift` should be used. * For version-specific manifests, the tools version specified in the filename should be used. For example, for `Package@swift-4.2.swift` it would be `4.2`. The tools version in the manifest must match that in the filename. -## Version-specific tags +### 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](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/Usage.md#version-specific-tag-selection) are not + supported by package collections. -## Configuration File +### 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](). +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. -# Example +## Example ```json { @@ -269,3 +295,101 @@ and preferences such as those set by the `--trust-unsigned` and `--skip-signatur ] } ``` + + +## Signing and protecting package collections + +Package collections can be signed to establish authenticity and protect their integrity. +Doing this is optional. +Users will be prompted 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 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 + +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 + +[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. +- **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: +- Require signature check on their collections — this defends against "signature stripping". +- Restrict what certificate can be used for signing — this defends against "signature replacement". + +The process for collection publishers to define their certificate-pinning configuration is as follows: +1. Edit [`PackageCollectionSourceCertificatePolicy`](https://github.com/swiftlang/swift-package-manager/blob/main/Sources/PackageCollections/PackageCollections%2BCertificatePolicy.swift) and add an entry to the `defaultSourceCertPolicies` dictionary: + +```swift +private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] = [ + // The key should be the "host" component of the package collection URL. + // This would require all package collections hosted on this domain to be signed. + "www.example.com": CertificatePolicyConfig( + // The signing certificate must have this subject user ID + certPolicyKey: CertificatePolicyKey.default(subjectUserID: "exampleUserID"), + /* + To compute base64-encoded string of a certificate: + let certificateURL = URL(fileURLWithPath: ) + let certificateData = try Data(contentsOf: certificateURL) + let base64EncoodedCertificate = certificateData.base64EncodedString() + */ + base64EncodedRootCerts: [""] + ) +] +``` + +2. Open a pull request for review. The requestor must be able to provide proof of their identity and ownership on the domain: + - The requestor must provide the actual certificate files (DER-encoded). The SwiftPM team will verify that the certificate chain is valid and the values provided in the PR are correct. + - The requestor must add a TXT record referencing the pull request. The SwiftPM team will run `dig -t txt ` to verify. This would act as proof of domain ownership. +3. After the changes are accepted, they will take effect in the next SwiftPM release. + +Since certificate-pinning configuration is associated with web domains, it can only be applied to signed collections hosted on the web (i.e., URL begins with `https://`) and does +not cover those found on local file system (i.e., URL begins with `file://`). + diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md index 86d36a97510..c404175b206 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionAdd.md @@ -29,6 +29,73 @@ $ swift package-collection add https://www.example.com/packages.json [--order N] 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](). + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. +``` + +Users may continue adding the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: + +```bash +$ 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: + +```bash +$ swift package-collection add https://www.example.com/bad-packages.json +The collection is missing required signature, which means it might have been compromised. +``` + +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. + +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: + +```bash +$ swift package-collection add https://www.example.com/packages.json +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. + +#### Unsigned package collections + +Users will get an error when trying to add an unsigned package collection: + +```bash +$ 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: + +```bash +$ swift package-collection add https://www.example.com/packages.json --trust-unsigned +``` + +The `--skip-signature-check` flag has no effects on unsigned collections. + + ## Usage ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md index 4f449d40fbb..03622359a39 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionDescribe.md @@ -11,6 +11,71 @@ Get metadata for a collection or a package included in an imported collection. This subcommand shows metadata for a collection or a package included in an imported collection. The result can optionally be returned as JSON using `--json` for integration into other tools. +### Metadata and packages of a collection + +`describe` can be used for both collections that have been previously added to the list of the user's configured collections, as well as to preview any other collections. + +```bash +$ swift package-collection describe [--json] https://www.example.com/packages.json +Name: Sample Package Collection +Source: https://www.example.com/packages.json +Description: ... +Keywords: best, packages +Created At: 2020-05-30 12:33 +Packages: + https://github.com/jpsim/yams + ... +``` + +#### Signed package collections + +If a collection is signed, SwiftPM will check that the signature is valid before showing a preview. + +```bash +$ swift package-collection describe https://www.example.com/bad-packages.json +The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. +``` + +Users may continue previewing the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: + +```bash +$ swift package-collection describe https://www.example.com/packages.json --skip-signature-check +``` + +### Metadata of a package + +`describe` can also show the metadata of a package included in an imported collection: + +```bash +$ swift package-collection describe [--json] https://github.com/jpsim/yams +Description: A sweet and swifty YAML parser built on LibYAML. +Available Versions: 4.0.0, 3.0.0, ... +Stars: 14 +Readme: https://github.com/jpsim/Yams/blob/master/README.md +Authors: @norio-nomura, @jpsim +-------------------------------------------------------------- +Latest Version: 4.0.0 +Package Name: Yams +Modules: Yams, CYaml +Supported Platforms: iOS, macOS, Linux, tvOS, watchOS +Supported Swift Versions: 5.3, 5.2, 5.1, 5.0 +License: MIT +``` + +### Metadata of a package version + +User may view additional metadata for a package version by passing `--version`: + +```bash +$ swift package-collection describe [--json] --version 4.0.0 https://github.com/jpsim/yams +Package Name: Yams +Version: 4.0.0 +Modules: Yams, CYaml +Supported Platforms: iOS, macOS, Linux, tvOS, watchOS +Supported Swift Versions: 5.3, 5.2, 5.1, 5.0 +License: MIT +``` + ## Usage ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md index a869a20bff0..07802d879f9 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections/PackageCollectionSearch.md @@ -11,6 +11,29 @@ Search for packages by keywords or module names. This subcommand searches for packages by keywords or module names within imported collections. The result can optionally be returned as JSON using `--json` for integration into other tools. +### String-based search + +The search command does a string-based search when using the `--keywords` option and returns the list of packages that matches the query: + +```bash +$ swift package-collection search [--json] --keywords yaml +https://github.com/jpsim/yams: A sweet and swifty YAML parser built on LibYAML. +... +``` + +### Module-based search + +The search command does a search for a specific module name when using the `--module` option: + +```bash +$ swift package-collection search [--json] --module yams +Package Name: Yams +Latest Version: 4.0.0 +Description: A sweet and swifty YAML parser built on LibYAML. +-------------------------------------------------------------- +... +``` + ## Usage ``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md deleted file mode 100644 index 94820b9872c..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionAddGuide.md +++ /dev/null @@ -1,92 +0,0 @@ -# Adding packages - -Learn how to add a package to your collection. - -## Overview - -The [`add` subcommand]() adds a package collection hosted on the web (HTTPS required): - -```bash -$ swift package-collection add https://www.example.com/packages.json -Added "Sample Package Collection" to your package collections. -``` - -Or found in the local file system: - -```bash -$ swift package-collection add file:///absolute/path/to/packages.json -Added "Sample Package Collection" to your package collections. -``` - -The optional `order` hint can be used to order collections and may potentially influence ranking in search results: - -```bash -$ swift package-collection add https://www.example.com/packages.json [--order N] -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](). - -```bash -$ swift package-collection add https://www.example.com/bad-packages.json -The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. -``` - -Users may continue adding the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: - -```bash -$ 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: - -```bash -$ swift package-collection add https://www.example.com/bad-packages.json -The collection is missing required signature, which means it might have been compromised. -``` - -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. - -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: - -```bash -$ swift package-collection add https://www.example.com/packages.json -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. - -#### Unsigned package collections - -Users will get an error when trying to add an unsigned package collection: - -```bash -$ 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: - -```bash -$ swift package-collection add https://www.example.com/packages.json --trust-unsigned -``` - -The `--skip-signature-check` flag has no effects on unsigned collections. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md deleted file mode 100644 index 24d3f3109b4..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionDescribeGuide.md +++ /dev/null @@ -1,73 +0,0 @@ -# Showing package collection metadata - -Discover more about package collections and their packages. - -## Overview - -The [`describe` subcommand]() shows metadata for a collection or a package included in an imported collection. The result can optionally be returned as JSON using `--json` for -integration into other tools. - -### Metadata and packages of a collection - -`describe` can be used for both collections that have been previously added to the list of the user's configured collections, as well as to preview any other collections. - -```bash -$ swift package-collection describe [--json] https://www.example.com/packages.json -Name: Sample Package Collection -Source: https://www.example.com/packages.json -Description: ... -Keywords: best, packages -Created At: 2020-05-30 12:33 -Packages: - https://github.com/jpsim/yams - ... -``` - -#### Signed package collections - -If a collection is signed, SwiftPM will check that the signature is valid before showing a preview. - -```bash -$ swift package-collection describe https://www.example.com/bad-packages.json -The collection's signature is invalid. If you would like to continue please rerun command with '--skip-signature-check'. -``` - -Users may continue previewing the collection despite the error or preemptively skip the signature check on a package collection by passing the `--skip-signature-check` flag: - -```bash -$ swift package-collection describe https://www.example.com/packages.json --skip-signature-check -``` - -### Metadata of a package - -`describe` can also show the metadata of a package included in an imported collection: - -```bash -$ swift package-collection describe [--json] https://github.com/jpsim/yams -Description: A sweet and swifty YAML parser built on LibYAML. -Available Versions: 4.0.0, 3.0.0, ... -Stars: 14 -Readme: https://github.com/jpsim/Yams/blob/master/README.md -Authors: @norio-nomura, @jpsim --------------------------------------------------------------- -Latest Version: 4.0.0 -Package Name: Yams -Modules: Yams, CYaml -Supported Platforms: iOS, macOS, Linux, tvOS, watchOS -Supported Swift Versions: 5.3, 5.2, 5.1, 5.0 -License: MIT -``` - -### Metadata of a package version - -User may view additional metadata for a package version by passing `--version`: - -```bash -$ swift package-collection describe [--json] --version 4.0.0 https://github.com/jpsim/yams -Package Name: Yams -Version: 4.0.0 -Modules: Yams, CYaml -Supported Platforms: iOS, macOS, Linux, tvOS, watchOS -Supported Swift Versions: 5.3, 5.2, 5.1, 5.0 -License: MIT -``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md deleted file mode 100644 index 11e4e13c1a6..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionListGuide.md +++ /dev/null @@ -1,15 +0,0 @@ -# List existing package collections - -Discover user-configured package collections. - -## Overview - -List [`list` subcommand]() lists all collections that are configured by the user: - -```bash -$ swift package-collection list [--json] -Sample Package Collection - https://example.com/packages.json -... -``` - -The result can optionally be returned as JSON using `--json` for integration into other tools. diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md deleted file mode 100644 index bd373c4941e..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRefreshGuide.md +++ /dev/null @@ -1,15 +0,0 @@ -# Refreshing package collection data - -Refresh the cached data for package collections. - -## Overview - -The [`refresh` subcommand]() refreshes any cached data manually: - -```bash -$ swift package-collection refresh -Refreshed 5 configured package collections. -``` - -SwiftPM will also automatically refresh data under various conditions, but some queries such as search will rely on locally cached data. - diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md deleted file mode 100644 index 0b6dc111e5d..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionRemoveGuide.md +++ /dev/null @@ -1,12 +0,0 @@ -# Removing packages - -Learn how to remove a package from a collection. - -## Overview - -The [`remove` subcommand]() removes a collection from the user's list of configured collections: - -```bash -$ swift package-collection remove https://www.example.com/packages.json -Removed "Sample Package Collection" from your package collections. -``` diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md deleted file mode 100644 index 3d7edee1683..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSearchGuide.md +++ /dev/null @@ -1,32 +0,0 @@ -# Querying for packages in package collections - -Find packages in a configured Package Collection. - -## Overview - -The [`search` subcommand]() searches for packages by keywords or module names within imported collections. The result can optionally be returned as JSON using `--json` for -integration into other tools. - -### String-based search - -The search command does a string-based search when using the `--keywords` option and returns the list of packages that matches the query: - -```bash -$ swift package-collection search [--json] --keywords yaml -https://github.com/jpsim/yams: A sweet and swifty YAML parser built on LibYAML. -... -``` - -### Module-based search - -The search command does a search for a specific module name when using the `--module` option: - -```bash -$ swift package-collection search [--json] --module yams -Package Name: Yams -Latest Version: 4.0.0 -Description: A sweet and swifty YAML parser built on LibYAML. --------------------------------------------------------------- -... -``` - diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md deleted file mode 100644 index cec31319fc6..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollectionSigning.md +++ /dev/null @@ -1,100 +0,0 @@ -# Signing and protecting package collections - -Learn how to protect and configure a signed package collection. - -## Overview - -Package collections can be signed to establish authenticity and protect their integrity. -Doing this is optional. -Users will be prompted 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 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 - -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 - -[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. -- **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: -- Require signature check on their collections — this defends against "signature stripping". -- Restrict what certificate can be used for signing — this defends against "signature replacement". - -The process for collection publishers to define their certificate-pinning configuration is as follows: -1. Edit [`PackageCollectionSourceCertificatePolicy`](https://github.com/swiftlang/swift-package-manager/blob/main/Sources/PackageCollections/PackageCollections%2BCertificatePolicy.swift) and add an entry to the `defaultSourceCertPolicies` dictionary: - -```swift -private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] = [ - // The key should be the "host" component of the package collection URL. - // This would require all package collections hosted on this domain to be signed. - "www.example.com": CertificatePolicyConfig( - // The signing certificate must have this subject user ID - certPolicyKey: CertificatePolicyKey.default(subjectUserID: "exampleUserID"), - /* - To compute base64-encoded string of a certificate: - let certificateURL = URL(fileURLWithPath: ) - let certificateData = try Data(contentsOf: certificateURL) - let base64EncoodedCertificate = certificateData.base64EncodedString() - */ - base64EncodedRootCerts: [""] - ) -] -``` - -2. Open a pull request for review. The requestor must be able to provide proof of their identity and ownership on the domain: - - The requestor must provide the actual certificate files (DER-encoded). The SwiftPM team will verify that the certificate chain is valid and the values provided in the PR are correct. - - The requestor must add a TXT record referencing the pull request. The SwiftPM team will run `dig -t txt ` to verify. This would act as proof of domain ownership. -3. After the changes are accepted, they will take effect in the next SwiftPM release. - -Since certificate-pinning configuration is associated with web domains, it can only be applied to signed collections hosted on the web (i.e., URL begins with `https://`) and does -not cover those found on local file system (i.e., URL begins with `file://`). diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollections.md deleted file mode 100644 index 6bb59611a49..00000000000 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollectionsGuide/PackageCollections.md +++ /dev/null @@ -1,49 +0,0 @@ -# Package Collections - -Learn to create 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. - -## Using the package-collection CLI - -With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. -Contents of imported package -collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). - -`swift package-collection` has the following subcommands: -- [`add`](): Add a new collection -- [`describe`](): Get metadata for a collection or a package included in an imported collection -- [`list`](): List configured collections -- [`refresh`](): Refresh configured collections -- [`remove`](): Remove a configured collection -- [`search`](): Search for packages by keywords or module names within imported collections - -## Topics - -### Getting Started -- -- - -### Modifying Package Collections -- -- -- - -### Inspecting Package Collections -- -- -- - From 0fa982103b0b934e3ef49a397949f12596e5f1f8 Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Mon, 26 May 2025 14:32:18 -0400 Subject: [PATCH 10/12] Update TODOs --- .../Documentation.docc/PackageCollections.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index eee23bb7159..fba9021387e 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -21,7 +21,7 @@ engineering teams, focusing them on a trusted set of vetted packages. With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package -collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). +collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). f `swift package-collection` has the following subcommands: - [`add`](): Add a new collection @@ -64,7 +64,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](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/Registry.md#36-package-identification) of the package if published to 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.** @@ -140,7 +140,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 [documentation](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/PackageRegistry/PackageRegistryUsage.md#package-signing) 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. @@ -149,7 +149,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)](https://github.com/swiftlang/swift-package-manager/blob/main/Documentation/Usage.md#version-specific-manifest-selection) . The keys of the `manifests` map are Swift tools (semantic) versions: * For `Package.swift`, the tools version specified in `Package.swift` should be used. @@ -157,7 +157,7 @@ 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 + [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. ### Configuration File From d115314b9ef7fdea5342928d210769b6bdbd5c0b Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Mon, 26 May 2025 15:14:18 -0400 Subject: [PATCH 11/12] Remove PackageCollectionAddGuide file --- .../PackageManagerDocs/PackageCollectionAddGuide.md | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 Sources/PackageManagerDocs/PackageCollectionAddGuide.md diff --git a/Sources/PackageManagerDocs/PackageCollectionAddGuide.md b/Sources/PackageManagerDocs/PackageCollectionAddGuide.md deleted file mode 100644 index 6c0a0313166..00000000000 --- a/Sources/PackageManagerDocs/PackageCollectionAddGuide.md +++ /dev/null @@ -1,11 +0,0 @@ -# Article - -Summary - -## Overview - -Text - -### Section header - -Text From 33f6f67fec6f567d071c7473140af4ac7c30c4c6 Mon Sep 17 00:00:00 2001 From: Bri Peticca Date: Fri, 30 May 2025 15:54:11 -0400 Subject: [PATCH 12/12] Add link to libswiftpm guide + update libswiftpm article title and overview --- .../Documentation.docc/PackageCollections.md | 2 +- .../Documentation.docc/SwiftPMAsALibrary.md | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md index 9dd0c6b5d94..6ccb0765538 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md +++ b/Sources/PackageManagerDocs/Documentation.docc/PackageCollections.md @@ -21,7 +21,7 @@ engineering teams, focusing them on a trusted set of vetted packages. With the `swift package-collection` command-line interface, SwiftPM users can subscribe to package collections. Contents of imported package -collections are accessible to any clients of [libSwiftPM](libSwiftPM.md). +collections are accessible to any clients of [libSwiftPM](). `swift package-collection` has the following subcommands: - [`add`](): Add a new collection diff --git a/Sources/PackageManagerDocs/Documentation.docc/SwiftPMAsALibrary.md b/Sources/PackageManagerDocs/Documentation.docc/SwiftPMAsALibrary.md index 4c58e4eb034..75870fb50a6 100644 --- a/Sources/PackageManagerDocs/Documentation.docc/SwiftPMAsALibrary.md +++ b/Sources/PackageManagerDocs/Documentation.docc/SwiftPMAsALibrary.md @@ -1,4 +1,4 @@ -# SwiftPM as a library +# Swift Package Manager as a library Include Swift Package Manager as a dependency in your Swift package. @@ -6,10 +6,8 @@ Include Swift Package Manager as a dependency in your Swift package. > Warning: **The libSwiftPM API is _unstable_ and may change at any time.** -SwiftPM has a library based architecture and the top-level library product is -called `libSwiftPM`. Other packages can add SwiftPM as a package dependency and -create powerful custom build tools on top of `libSwiftPM`. +Swift Package Manager has a library based architecture and the top-level library product is called `libSwiftPM`. +Other packages can add SwiftPM as a package dependency and create powerful custom build tools on top of `libSwiftPM`. -A subset of `libSwiftPM` that includes only the data model (without SwiftPM's -build system) is available as `libSwiftPMDataModel`. Any one client should -depend on one or the other, but not both. +A subset of `libSwiftPM` that includes only the data model (without the package manager's build system) is available as `libSwiftPMDataModel`. +Any one client should depend on one or the other, but not both.