Swift Package Registry Service

Normative References

  • RFC 2119: Key words for use in RFCs to Indicate Requirement Levels
  • RFC 3230: Instance Digests in HTTP
  • RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
  • RFC 4880: OpenPGP Message Format
  • RFC 5843: Additional Hash Algorithms for HTTP Instance Digests
  • RFC 6249: Metalink/HTTP: Mirrors and Hashes
  • RFC 6570: URI Template
  • RFC 7230: Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
  • RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content
  • RFC 7233: Hypertext Transfer Protocol (HTTP/1.1): Range Requests
  • RFC 7234: Hypertext Transfer Protocol (HTTP/1.1): Caching
  • RFC 7807: Problem Details for HTTP APIs
  • RFC 8288: Web Linking
  • SemVer: Semantic Versioning

Informative References

  • BCP 13 Media Type Specifications and Registration Procedures
  • RFC 6749: The OAuth 2.0 Authorization Framework
  • RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
  • TR36: Unicode Technical Report #36: Unicode Security Considerations
  • JSON-LD: A JSON-based Serialization for Linked Data
  • Schema.org A shared vocabulary for structured data.

Security

A package registry can offer stronger guarantees for safety and security compared to downloading dependencies using Git. Providing a checksum for the source archive of a package release allows a client to validate the integrity of the downloaded content. Providing a digital signature allows a server to certify that content to a client in a verifiable way.

We acknowledge an inherent privacy concern with repository hosts and package registries logging the IP addresses for each package requested. The use of proxies and other techniques can help mitigate this risk, but we believe the best solution is for services to operate according to a stated privacy policy.

Impact on existing packages

Current packages won't be affected by this change, as they'll continue to be able to download dependencies directly through Git.

Swift developers can opt-in to package registries on a per-dependency basis by changing its URL from one that points to a repository to one that resolves to a package endpoint.

  let package = Package(
      name: "MyPackage",
      dependencies: [
-        .package(url: "https://github.com/apple/swift-argument-parser.git", from: "0.0.1"),
+        .package(url: "https://swift.pkg.github.com/apple/swift-argument-parser", from: "0.0.1"),
      ]

Alternatives considered

We first considered the more traditional "push"-based package registry design. However, this model creates a separate release process that runs parallel to version control, which not only duplicates effort but has the potential to introduce discrepancies between tags and releases.

Future directions

Defining a standard interface for package registries lays the groundwork for several useful features.

Swift Package Manager integration

A package registry can be useful in its own right, but enjoying its full benefit requires additional functionality in Swift Package Manager. We intend to submit a separate proposal for doing this.

Offline cache

Swift Package Manager could implement an offline cache that allows it to work without network access. While this is technically possible today, a package registry allows for a simpler and more secure implementation than would otherwise be possible with Git repositories alone.

Security auditing

The response for listing package releases could be updated to include information about security advisories.

/* straw-man proposal */
{
    "releases": { /* ... */ },
    "advisories": [{
        "cve": "CVE-20XX-12345",
        "cwe": "CWE-400",
        "package_name": "mona/LinkedList",
        "vulnerable_versions": "<=1.0.0",
        "patched_versions": ">1.0.0",
        "severity": "moderate",
        "recommendation": "Update to version 1.0.1 or later.",
        /* additional fields */
    }]
}

Swift Package Manager could communicate this information to users when installing or updating dependencies or as part of a new swift package audit subcommand.

$ swift package audit
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ RegEx                                                        │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ PatternMatcher                                               │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ SomePackage > PatternMatcher > RegEx                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://example.com/advisories/526                           │
└───────────────┴──────────────────────────────────────────────────────────────┘

Found 3 vulnerability (1 low, 1 moderate, 1 high) in 12 scanned packages.
  Run `swift package audit fix` to fix 3 of them.

Package removal reason

The request for unpublishing a package could be amended to accept additional parameters in the request body that explain why a package is being removed. For example, a maintainer could unpublish a package release in response to a security vulnerability or because they didn't intend to publish it in the first place. This endpoint could also be amended to distinguish between removal and deprecation of package releases.

Binary framework distribution

The package registry specification could be amended to add support for distributing packages as XCFramework bundles.

GET /mona/LinkedList/1.1.1.xcframework HTTP/1.1
Accept: application/vnd.apple.xcframework
Accept-Version: 1

Swift Package Manager could then use XCFramework archives as binary dependencies or as part of a future binary artifact distribution mechanism.

let package = Package(
    name: "SomePackage",
    /* ... */
    targets: [
        .binaryTarget(
            name: "LinkedList",
            url: "https://swift.pkg.github.com/mona/LinkedList/1.1.1.xcframework",
            checksum: "ed04a550c2c7537f2a02ab44dd329f9e74f9f4d3e773eb883132e0aa51438b37"
        ),
    ]
)
21 Likes