[Pitch] Software Bill of Materials (SBOM) Generation for Swift Package Manager

Introduction

An SBOM (Software Bill of Materials) provides a detailed inventory of software components included in an artifact. SBOMs allow developers to improve and analyze the software supply chain security profile for their Swift projects (for example, determining whether a dependency that's being used has a vulnerability). Also, some companies, governments, and other regulatory bodies require SBOMs to be produced for auditing purposes.

There are two common formats for SBOMs: CycloneDX and SPDX.

Motivation

Currently, Swift Package Manager lacks built-in support for generating SBOMs. Instead, developers have to rely on external or third-party tools to create SBOMs. External and third-party tools usually analyze the Package.swift and Package.resolved files for package dependencies, so information about what product uses which dependencies is missing.

Proposed Solution

This pitch describes adding CycloneDX and SPDX SBOM generation capabilities to Swift Package Manager as part of the build command and as a separate package subcommand.

Integrated Build Command

swift build will take an optional flag --sbom-spec that triggers CycloneDX and/or SPDX SBOM generation as part of the build command. SwiftPM will analyze the resolved package graph and optionally the SwiftBuild build system’s dependency graph, and produce SBOMs for the root package or product.

Re-running the command will not overwrite previously generated SBOMs; timestamps will be appended to SBOMs. This is to address the case when the same product or package is intentionally built multiple times with different flags; all SBOMs (not just the most recent) are relevant to the user.

If SBOM generation fails, the build will return an error.

Traits and Conditions

Dependencies affected by traits are taken into consideration during package resolution. SwiftPM’s resolved package graph will already reflect the impact of traits on dependencies.

Conditions (e.g., OS-specific dependencies) are evaluated at build-time. SwiftPM’s package graph does not reflect conditions. Instead, the SBOM command will look at SwiftBuild build system’s computed dependency graph to determine which dependencies from the package graph should be included or excluded in the final SBOMs.

Incremental Builds

SBOM generation is not incremental, so if SBOM generation is specified, the build will always produce new SBOMs, even if the artifacts have not changed since the last build.

SBOM generation does not affect whether an artifact build will be full or incremental.

CLI Examples

A user can run the following commands:

# To generate CycloneDX SBOM file for a package using both package graph and build graph
$ swift build --build-system swiftbuild --sbom-spec cyclonedx

# To generate SPDX SBOM file for a package using both package graph and build graph
$ swift build --build-system swiftbuild --sbom-spec spdx

# To generate CycloneDX and SPDX SBOM files for a package using only the package graph
$ swift build --sbom-spec cyclonedx --sbom-spec spdx

# To generate a CycloneDX or SPDX SBOM file for a single product using both package graph and build graph
$ swift build --build-system swiftbuild --product MyProduct1 --sbom-spec cyclonedx
$ swift build --build-system swiftbuild --product MyProduct2 --sbom-spec spdx

# To generate SBOM files into a specific directory
$ swift build --build-system swiftbuild --sbom-spec cyclonedx --sbom-spec spdx --sbom-dir /MyDirectory

Optional Flags

--sbom-spec will trigger SBOM generation when a build is run. Either cyclonedx or spdx or both can be passed to indicate what kind of SBOMs to generate.

--sbom-spec can only be used with one of the following:

  • without --product and without --target flags (i.e., a SBOM for the entire package), or
  • with --product flag (i.e., a SBOM for a specific product)

The build will error if --sbom-spec is used with the --target flag.

If --build-system swiftbuild is not specified, a warning will be emitted that only the package graph is being used for SBOM generation. (The build dependency graph is only available through SwiftBuild.)

cyclonedx and spdx flags will always point to the most recently SwiftPM-supported major versions, but users have the option to specify the major version they'd like.

OPTIONS:
  --sbom-spec <spec>           Set the SBOM specification.
        cyclonedx         - Most recent major version of CycloneDX supported by SwiftPM (currently: 1.7)
        spdx              - Most recent major version of SPDX supported by SwiftPM (currently: 3.0.1)
        cyclonedx1        - Most recent minor version of CycloneDX v1 supported by SwiftPM  (currently: 1.7)
        spdx3             - Most recent minor version of SPDX v3 supported by SwiftPM  (currently: 3.0.1)
        # Future: cyclonedx2...
        # Future: spdx4...

Additionally, users can specify the following optional flags (which must appear with --sbom-spec):

--sbom-dir <sbom-dir>  The absolute or relative directory path to generate the SBOM(s) in.
--sbom-filter <filter> Filter the SBOM components and dependencies by products and/or packages.
        all               - Include all entities in the SBOM (default)
        package           - Only include package information and package dependencies
        product           - Only include product information and product dependencies

Configuration

Environment variables can be used for SBOM generation configuration in the short-term.

An issue in Github will be raised to address changing SBOM environment variables to a configuration file.

  • SWIFTPM_BUILD_SBOM_DIRECTORY: specifies which directory the SBOMs should be generated in. If --sbom-dir is passed to swift build, --sbom-dir will take precedence.
  • SWIFTPM_BUILD_SBOM_FILTER: specifies which filter to apply, defaults to all. If --sbom-filter is passed to swift build, --sbom-filter will take precedence.
  • (Needs further discussion) SWIFTPM_BUILD_SBOM_WITHOUT_FAILURE: automatically generates both CycloneDX and SPDX SBOMs as part of the swift build command. If --sbom-spec is passed to swift build, --sbom-spec will take precedence. A failure in SBOM generation will not cause the build to fail.
    • This addresses the use case where an external party (e.g., infrastructure or security teams) wants to generate SBOMs for all Swift projects under their purview without interfering with build results.
    • Alternatives include:
      • A specific exit code to use when the build passes but SBOM generation fails (e.g., permission to write to SBOM folder is denied). However, this would cause most CI pipelines to still fail, unless an exception is built into the CI system, so this is not ideal for most infrastructure and security teams.
      • An additional environment variable SWIFTPM_BUILD_SBOM_WITH_FAILURE that automatically generates CycloneDX and SPDX SBOMs as part of the swift build command. A failure in SBOM generation will cause the build to fail (i.e., default behavior, but without changing the swift build command that teams have written).
        • For example, if a team is using the --target flag, the build will pass, but the build exit code will be a failure code because SBOM generation does not work with --target.
      • Two environment variables, SWIFTPM_BUILD_SBOM (default: false) and SWIFTPM_SBOM_RECORD_FAILURE (default: true) that toggle whether to build SBOMs automatically and whether to fail the build if SBOM generation fails. This would also necessitate adding a --sbom-record-failure flag to the CLI, so that CLI and environment variables match.

Package Subcommand

SBOM generation will also be added as a separate subcommand swift package generate-sbom. It will share the same SBOM flags as SBOM generation for swift build. Unlike SBOM generation in swift build, swift package generate-sbom will not call the build or use the SwiftBuild build dependency graph.

This subcommand is to address use cases where an SBOM might need to be created after a build (for example, in a CICD pipeline or using a different version of the toolchain), but calling swift build again is undesirable or impossible.

The subcommand will always emit a warning that the SBOM may not be fully accurate because it only uses the package graph. The user will have the option to pass --disable-automatic-resolution to force SBOM generation to fail if the Package.resolved is not up-to-date.

Note: Using the package subcommand can result in dependency resolution timing issues. There is an edge case where an artifact is built, the dependency graph changes, and then the SBOM is generated. In that case, the SBOM will not accurately reflect the built artifact’s components and dependencies.

CLI Examples

A user can run the following commands:

# To generate CycloneDX SBOM file for a package using the package graph
$ swift package generate-sbom --sbom-spec cyclonedx

# To generate SPDX SBOM file for a package using the package graph
$ swift package generate-sbom --sbom-spec spdx

# To generate CycloneDX and SPDX SBOM files for a package using the package graph
$ swift package generate-sbom --sbom-spec cyclonedx --sbom-spec spdx

# To generate a CycloneDX or SPDX SBOM file for a single product using the package graph
$ swift package generate-sbom --product MyProduct1 --sbom-spec cyclonedx
$ swift package generate-sbom --product MyProduct2 --sbom-spec spdx

# To generate SBOM files into a specific directory
$ swift package generate-sbom --sbom-spec cyclonedx --sbom-spec spdx --sbom-dir /MyDirectory

Design

The SBOM generation will have three layers:

  1. Extractor: Reads information from the package graph and build dependency graph and saves it into internal data structures
  2. Converters: Read information from internal data structures and convert them into CycloneDX and SPDX equivalent structures
  3. Validator: Reads CycloneDX and SPDX SBOM JSON objects and validates them against the appropriate schema

SBOM Content

This feature will support the most recent minor versions of major versions starting with CycloneDX 1 and SPDX 3.

Only JSON files will be generated. JSON is a common file format supported by both CycloneDX and SPDX. JSON is the preferred format for CycloneDX and becoming more common in SPDX.

Generated SBOMs will include:

Components

  • Component CycloneDX type or package SPDX purpose; name; and version
  • Package URL (PURL) for unique identification
  • Source repository information

CycloneDX:

{
    "bom-ref" : "swift-asn1:SwiftASN1",
    "name" : "SwiftASN1",
    "pedigree" : {
        "commits" : [
            {
                 "uid" : "40d25bbb2fc5b557a9aa8512210bded327c0f60d",
                 "url" : "https://github.com/apple/swift-asn1.git"
            }
        ]
    },
    "properties" : [
        {
            "name" : "swift-entity",
            "value" : "swift-product"
        }
    ],
    "purl" : "pkg:swift/github.com/apple/swift-asn1:SwiftASN1@1.5.0",
    "scope" : "required",
    "type" : "library",
    "version" : "1.5.0"
}

SPDX:

{
    "creationInfo" : "_:creationInfo",
    "description" : "<ResolvedPackage: swift-asn1>",
    "externalUrl" : "pkg:swift/github.com/apple/swift-asn1@1.5.0",
    "name" : "swift-asn1",
    "software_internalVersion" : "1.5.0",
    "software_primaryPurpose" : "library",
    "spdxId" : "urn:spdx:swift-asn1",
    "summary" : "swift-package",
    "type" : "software_Package"
},
{
    "creationInfo" : "_:creationInfo",
    "from" : "urn:spdx:40d25bbb2fc5b557a9aa8512210bded327c0f60d",
    "relationshipType" : "generates",
    "spdxId" : "urn:spdx:40d25bbb2fc5b557a9aa8512210bded327c0f60d-generates",
    "to" : [
        "urn:spdx:swift-asn1",
        "urn:spdx:swift-asn1:SwiftASN1"
    ],
    "type" : "Relationship"
},
{
    "externalIdentifierType" : "gitoid",
    "identifier" : "urn:spdx:40d25bbb2fc5b557a9aa8512210bded327c0f60d",
    "identifierLocator" : [
        "https://github.com/apple/swift-asn1.git"
    ],
    "type" : "ExternalIdentifier"
}

Dependencies

  • Direct and transitive relationships
  • Package-to-package dependencies (only packages used by the root package or specified product)
  • Package-to-product dependencies (i.e., a package depends on its own products)
  • Product-to-product dependencies (only products used by the root package or specified product)

CycloneDX:

{
    "dependsOn" : [
        "swift-asn1:SwiftASN1"
    ],
    "ref" : "swift-crypto:_CryptoExtras"
},
{
    "dependsOn" : [
        "swift-crypto:Crypto",
        "swift-crypto:_CryptoExtras",
        "swift-asn1"
    ],
    "ref" : "swift-crypto"
},
{
    "dependsOn" : [
        "swift-asn1",
        "swift-crypto",
        "swift-certificates:X509"
    ],
    "ref" : "swift-certificates"
},
{
    "dependsOn" : [
        "swift-crypto:Crypto",
        "swift-asn1:SwiftASN1",
        "swift-crypto:_CryptoExtras"
    ],
    "ref" : "swift-certificates:X509"
},
{
    "dependsOn" : [
        "swift-asn1:SwiftASN1"
    ],
    "ref" : "swift-asn1"
}

SPDX:

{
    "creationInfo" : "_:creationInfo",
    "from" : "urn:spdx:swift-crypto:_CryptoExtras",
    "relationshipType" : "dependsOn",
    "spdxId" : "urn:spdx:swift-crypto:_CryptoExtras-dependsOn",
    "to" : [
        "urn:spdx:swift-asn1:SwiftASN1"
    ],
    "type" : "Relationship"
},
{
    "creationInfo" : "_:creationInfo",
    "from" : "urn:spdx:swift-crypto",
    "relationshipType" : "dependsOn",
    "spdxId" : "urn:spdx:swift-crypto-dependsOn",
    "to" : [
        "urn:spdx:swift-crypto:Crypto",
        "urn:spdx:swift-crypto:_CryptoExtras",
        "urn:spdx:swift-asn1"
    ],
    "type" : "Relationship"
},
{
    "creationInfo" : "_:creationInfo",
    "from" : "urn:spdx:swift-certificates",
    "relationshipType" : "dependsOn",
    "spdxId" : "urn:spdx:swift-certificates-dependsOn",
    "to" : [
        "urn:spdx:swift-asn1",
        "urn:spdx:swift-crypto",
        "urn:spdx:swift-certificates:X509"
    ],
    "type" : "Relationship"
},
{
    "creationInfo" : "_:creationInfo",
    "from" : "urn:spdx:swift-certificates:X509",
    "relationshipType" : "dependsOn",
    "spdxId" : "urn:spdx:swift-certificates:X509-dependsOn",
    "to" : [
        "urn:spdx:swift-crypto:Crypto",
        "urn:spdx:swift-asn1:SwiftASN1",
        "urn:spdx:swift-crypto:_CryptoExtras"
    ],
    "type" : "Relationship"
},
{
    "creationInfo" : "_:creationInfo",
    "from" : "urn:spdx:swift-asn1",
    "relationshipType" : "dependsOn",
    "spdxId" : "urn:spdx:swift-asn1-dependsOn",
    "to" : [
        "urn:spdx:swift-asn1:SwiftASN1"
    ],
    "type" : "Relationship"
}

Metadata

  • SwiftPM version used
  • SBOM timestamp
  • Spec version

CycloneDX:

"metadata" : {
...
    "timestamp" : "2025-11-19T21:42:50Z",
    "tools" : {
        "components" : [
            {
                "bom-ref" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6",
                "licenses" : [
                    {
                        "license" : {
                            "id" : "Apache-2.0",
                            "url" : "http://swift.org/LICENSE.txt"
                         }
                    }
                ],
                "name" : "swift-package-manager",
                "purl" : "pkg:swift/github.com/swiftlang/swift-package-manager@6.3.0-dev",
                "scope" : "excluded",
                "type" : "application",
                "version" : "6.3.0-dev"
            }
        ]
    }
},
"serialNumber" : "urn:uuid:8318774a-f646-4eab-a08c-0dc3f952abc5",
"specVersion" : "1.7",
"version" : 1

SPDX:

{
    "creationInfo" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6:creationInfo",
    "from" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6",
    "relationshipType" : "hasDeclaredLicense",
    "spdxId" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6-hasDeclaredLicense-urn:spdx:Apache-2.0",
    "to" : [
        "urn:spdx:Apache-2.0"
    ],
    "type" : "Relationship"
},
{
    "creationInfo" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6:creationInfo",
    "simplelicensing_licenseExpression" : "Apache-2.0",
    "spdxId" : "urn:spdx:Apache-2.0",
    "type" : "simplelicensing_LicenseExpression"
},
{
    "@id" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6:creationInfo",
    "created" : "1970-01-01T00:00:00Z",
    "createdBy" : [
        "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6"
    ],
    "specVersion" : "6.3.0-dev",
    "type" : "CreationInfo"
},
{
    "creationInfo" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6:creationInfo",
    "name" : "swift-package-manager",
    "spdxId" : "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6",
    "type" : "Agent"
},
{
    "@id" : "_:creationInfo",
    "created" : "2025-11-19T21:42:50Z",
    "createdBy" : [
        "urn:uuid:40316357-938f-4a8c-9962-e928fbc251a6"
    ],
    "specVersion" : "3.0.1",
    "type" : "CreationInfo"
},
{
    "creationInfo" : "_:creationInfo",
    "profileConformance" : [
        "core",
        "software"
    ],
    "rootElement" : [
        "urn:spdx:swift-package-manager"
    ],
    "spdxId" : "urn:uuid:5aee3149-5395-4a41-a076-2491437026d3",
    "type" : "software_Sbom"
}

Primary Component

CycloneDX:

"component" : {
    "bom-ref" : "swift-package-manager",
    "name" : "swift-package-manager",
    "pedigree" : {
        "commits" : [
            {
                "uid" : "37990426e3f1cb4344f39641e634c76130c1fb42",
                "url" : "git@github.com:echeng3805/swift-package-manager.git"
            }
        ]
    },
    "properties" : [
        {
            "name" : "swift-entity",
            "value" : "swift-package"
        }
    ],
    "purl" : "pkg:swift/github.com/echeng3805/swift-package-manager@37990426e3f1cb4344f39641e634c76130c1fb42-modified",
    "scope" : "required",
    "type" : "application",
    "version" : "37990426e3f1cb4344f39641e634c76130c1fb42-modified"
}

SPDX:

{
    "creationInfo" : "_:creationInfo",
    "description" : "<ResolvedPackage: swift-package-manager>",
    "externalUrl" : "pkg:swift/github.com/swiftlang/swift-package-manager@37990426e3f1cb4344f39641e634c76130c1fb42-modified",
    "name" : "swift-package-manager",
    "software_internalVersion" : "37990426e3f1cb4344f39641e634c76130c1fb42-modified",
    "software_primaryPurpose" : "application",
    "spdxId" : "urn:spdx:swift-package-manager",
    "summary" : "swift-package",
    "type" : "software_Package"
}

Security

This will strengthen Swift’s supply chain security profile by providing a basic inventory for packages and products.

Impact on Existing Packages

This feature doesn't modify existing SwiftPM functionality, like the build graph or dependency resolution. It adds an optional feature to the build command and a new package subcommand.

Alternatives Considered

Build Plugin

Build plugins are meant to generate auxiliary build artifacts. An SBOM isn’t really a build artifact; it’s metadata about build artifacts.

Command Plugin

Command plugins need to be added to the Package.swift file to be available. Building SBOM generation directly into swift build gives users the feature without any need to change existing Package.swift files or existing configuration.

Future Features

Some future features that can be added include:

  • Best attempt at licenses: Automatic license identification from source code (some edge cases make it difficult to exactly accurately determine licenses; examples: multi-license projects depending on whether payment was rendered, multiple licenses in the repository, license of single file vs license of whole project, changes in license verbiage without changing the name of the license, relicensing for different versions of the same project)
  • --target flag support: Support more granular SBOMs (per target)
  • Additional information: Maintainers’ contact information, commit/forking history, additional build metadata (e.g., host, operating system)
  • Additional file formats: XML, TV, YAML. XML is a format supported by both specs; however, XML is not the preferred format for either CycloneDX or SPDX.
  • Additional spec versions: CycloneDX 2, SPDX 4 when available
  • Merged SBOMs: Generate one SBOM for multiple products/targets, merge or link existing SBOM (e.g., from a third-party SDK) into output SBOM
  • Independent CycloneDX and SPDX libraries: For parsing CycloneDX/SPDX files, or supporting other fields besides the bare minimum
  • Package.resolved generation: Generate a Package.resolved file based on an SBOM in order to reproduce a dependency graph (e.g., for debugging)
  • SBOM signing: Sign the SBOM cryptographically to link it to an artifact
  • Hashes: Add hashes to the SBOM
28 Likes

This doesn’t seem accurate to me, the way things are proposed is that the SBOM can literally be another output of swift build which by definition is a build artifact. I would just merge this with the justification for not using command plugins below since the same considerations would apply.

1 Like

Thank you! I've made the change here. Alternatives considered now says: "Command and build plugins need to be added to the Package.swift file to be available. Building SBOM generation directly into swift build gives users the feature without any need to change existing Package.swift files or existing configuration."

The beginnings of a proposal can be found here. It contains the contents of the pitch, and will have additional information about implementation details in the future.

1 Like

Love this, and what it can enable, so +1 for the pitch right off the bat.

I do have some questions about how this tracks when the dependency you're working on is either an XCFramework or an .artifactBundle that contains a binary. Are those the boundary conditions for this pitch, and the SBOM analysis stops at identifying where they come from and the associated hash that the package manifest requires?

Is there any consideration (perhaps in a "Future Directions") for additional requirements on either/both XCFrameworks and .artifactBundles to embed the expectation of their own SBOMs in them, and allow them to be referenced?

Along those same lines, is there anything that needs to be accommodated within this to support static Linux SDK (or any other SDK - Windows, Android, a custom built embedded-oriented SDK, etc)? In particular, I was imagining that to enable this for SDKs, we may need to have information about the libraries that the SDKs bind into, especially for the static linked binaries that drag those pieces into the final binary size.

2 Likes

This is great! Supply chain security is becoming more and more important across all ecosystems and all deployment targets. Every year, the number of supply chain attacks increases. SBOMs are critical to produce better visibility into what software is running where and will help any team or organization to triage supply chain vulnerabilities more effectively. I think it is the right thing to integrate this directly into Swift PM, not only for the technical reasons outlined here but also to communicate a clear message that the Swift ecosystem takes supply chain security seriously. One of the core principles of Swift is to provide safe defaults, and in my personal opinion, producing SBOMs by default is inline with that.

3 Likes

To add to Franz’s point, requiring SBOM is often a broad policy for a team, so I'm glad to see that SwiftPM will support environment variables that can be set by a CI system, ensuring that every build invocation produces an SBOM file, rather than asking individual projects to explicitly opt in.

I might be misunderstanding you and/or @echeng3805, but isn't the pitch for an opt-in flag to generate a SBOM, rather than by default? Are you suggesting that swift build should generate a SBOM by default?

Yes, you are correct that SBOMs are opt-in: the pitch is for an opt-in flag to generate an SBOM, but there will also be configuration (currently, environment variables, until there's a more standard way of configuration) to turn on SBOM generation by default, so that every build generates SBOMs by default. This configuration has to be set at least once by the user or by the team(s) that owns CI pipelines.

  1. Yes, currently the pitch and prototype don't capture frameworks or bundles. I think frameworks and bundles might be tracked by SwiftPM outside the package graph, in another data structure (I am not sure about this)? The implementation only looks at ResolvedPackage, ResolvedProduct, and ResolvedModule in the package graph (cross-referenced against SwiftBuild's dependency graph optionally). So anything that's not in the package graph does not appear in the SBOM.

  2. Yes, there is the Merged SBOMs bullet point that sort of refers to this, where an existing SBOM could potentially be linked into the output SBOM. I think at the very least there would have to be a common output location for SBOMs (so SwiftPM can find the pre-existing SBOM), as well as parsing ability (to read the pre-existing SBOM and extract information from it to match it to the correct dependency in SwiftPM). Right now, the SBOM generation data flow only works in one direction (SwiftPM data structures extracted into SBOM, but not from SBOM parsed into SwiftPM data structures). I've added the two requirements (output location and parsing) to the Merged SBOMs bullet point in the proposal draft PR. (Unfortunately, adding the ability to parse SBOMs would more than double the scope of this pitch.)

  3. For SDKs, I think there's two cases. The first is if the SDK provides its own SBOM - this lines up with Merged SBOMs, where we would need a common location and SBOM parsing. If the SDK doesn't provide its own SBOM, then the SBOM generation would need to rely on SwiftPM entirely for name, version, provenance (e.g., URL), and dependencies/statically linked libraries for the SDK. (I am not sure what information SwiftPM keeps track of for SDKs right now though.) For implementation, there are a few ways to go about it. There could be an SBOMSDK struct that keeps track of all the information from SwiftPM for a single SDK, an sdks field in the internal SBOM struct, and then conversion that merges the sdks field into the output CycloneDX/SPDX SBOM's components and dependencies. This would be more opaque, because only the final SBOM is exposed. Or alternatively, a single SDK could produce its own SBOM, which is then merged or linked into the final SBOM. This would be more transparent, because the pieces going into the final SBOM are exposed. Anyway, that is to say that to support SBOMs for SDKs in the future, there might have to be some changes in SwiftPM to store/expose the appropriate SDK information, and then some code added to the SBOM generation to read the appropriate information; the SBOM generation design is flexible enough that SDKs should be able to be added as a future feature without needing to change the core design of reading SwiftPM info, storing the info internally, then converting to external formats.

1 Like

@echeng3805 awesome initiative. PURL lead maintainer here. We have a PURL library for Swift that is timely being brought up to date and we need also more support!

See Bring library up to date with latest PURL spec and test suite by pombredanne · Pull Request #2 · package-url/packageurl-swift · GitHub and Passing the baton? · Issue #3 · package-url/packageurl-swift · GitHub

4 Likes

In all cases, PURL is here for Swift!

1 Like