swift-package-manager: versionFingerprints fails for dependencies which use upToNextMajor

Description

Unable to build projects as fingerprint fails while doing swift package update:

error: Revision ac4fe4ca5039389f3502487cb4b23353c9d4e52a for flatbuffers remoteSourceControl https://github.com/mustiikhalil/flatbuffers version 2.0.8 does not match previously recorded value cb52bf560cf158e62accbaa225d06176929508cc
[...]
error: exhausted attempts to resolve the dependencies graph, with 'core-process remoteSourceControl [...]

This occours when using upToNextMajor() and a new commit is added to the tag after saving of the fingerprint.

For example in the above case, we have:

grep -C 1 fingerprint  ~/Library/org.swift.swiftpm/security/fingerprints/flatbuffers.json 
      "sourceControl" : {
        "fingerprint" : "cb52bf560cf158e62accbaa225d06176929508cc",
        "origin" : "https://github.com/mustiikhalil/flatbuffers"

The cb52bf5 is a previous commit to the tag, while latest one is ac4fe4c. All commits to 2.0.8 tag

Expected behavior

No response

Actual behavior

No response

Steps to reproduce

The most minimal setup would be 2 set up packages, one which depends on just branch and one which is versioned:

for project in package-branch package-versioned ; do
   mkdir $project && cd $project
   swift package init --type executable
   cd -
done

Set up 1 commit behind the head of the tag:

cat << EOF >  ~/Library/org.swift.swiftpm/security/fingerprints/flatbuffers.json 
{
  "versionFingerprints" : {
    "2.0.8" : {
      "sourceControl" : {
        "fingerprint" : "cb52bf560cf158e62accbaa225d06176929508cc",
        "origin" : "https://github.com/mustiikhalil/flatbuffers"
      }
    }
  }
}
EOF

Use up to next major, to latest tag currently available:

cat << EOF > package-versioned/Package.swift
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "package-versioned",
    platforms: [
        .macOS(.v12),
    ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "package-versioned",
            targets: ["package-versioned"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(url: "https://github.com/mustiikhalil/flatbuffers", .upToNextMajor(from: "2.0.8")),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "package-versioned",
            dependencies: [
                  .product(name: "FlatBuffers", package: "flatbuffers"),
        ]),
        .testTarget(
            name: "package-versionedTests",
            dependencies: ["package-versioned"]),
    ]
)
EOF

Branch version:

cat << EOF > package-branch/Package.swift
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "package-branch",
    platforms: [
        .macOS(.v12),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        .package(url: "https://github.com/mustiikhalil/flatbuffers", branch: "swift"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .executableTarget(
            name: "package-branch",
            dependencies: [
                .product(name: "FlatBuffers", package: "flatbuffers"),
        ]),
        .testTarget(
            name: "package-branchTests",
            dependencies: ["package-branch"]),
    ]
)
EOF

The package-branch will compile fine if the above fingerprint is used, but the package-versioned will have the fingerprint check fail, even when doing a full clean build and refresh:

swift package purge-cache; swift package clean; swift package reset;  swift package update; swift build

The package builds only fine when the fingerprint check is downgraded:

swift package update --resolver-fingerprint-checking=warn
Updating https://github.com/mustiikhalil/flatbuffers
Updated https://github.com/mustiikhalil/flatbuffers (0.58s)
Computing version for https://github.com/mustiikhalil/flatbuffers
Computed https://github.com/mustiikhalil/flatbuffers at 2.0.8 (0.02s)
warning: Revision ac4fe4ca5039389f3502487cb4b23353c9d4e52a for flatbuffers remoteSourceControl https://github.com/mustiikhalil/flatbuffers version 2.0.8 does not match previously recorded value cb52bf560cf158e62accbaa225d06176929508cc
Creating working copy for https://github.com/mustiikhalil/flatbuffers
Working copy of https://github.com/mustiikhalil/flatbuffers resolved at 2.0.8

The fingerprint functionally has been added in https://github.com/apple/swift-package-manager/pull/3890

Swift Package Manager version/commit hash

Swift 5.7.0

Swift & OS version (output of swift --version && uname -a)

swift --version && uname -a
swift-driver version: 1.62.3 Apple Swift version 5.7 (swiftlang-5.7.0.123.8 clang-1400.0.29.50)
Target: arm64-apple-macosx12.0
Darwin alpine.local 21.5.0 Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:37 PDT 2022; root:xnu-8020.121.3~4/RELEASE_ARM64_T6000 arm64

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 16 (9 by maintainers)

Most upvoted comments

I agree that the existing reset commands shouldn’t delete security-sensitive data, but it might be useful to have a flow to accept a single changed fingerprint vs. wiping the entire storage of them?

Also I think we should make the error more verbose, I have seen a few people be confused about them. One inspiration could be SSH’s handling of changed host fingerprints, IIRC it has some huge bold warning text at the beginning, but also mentions how to “fix” the issue by editing config files directly in the message.

iiuc @yim-lee point is that fingerprints and a few other things like configuration for collections and registries are ~global (~/.swiftpm) and having a single command to wipe them all is confusing local vs. global and may have unintended consequences. that said, having some narrow helper commands like purge-fingerprints could be helpful

One can purge all or specific fingerprints by cleaning up the DOT_SWIFTPM/security/fingerprints directory (e.g., ~/.swiftpm/security/fingerprints/ on macOS).

Maybe we can consider adding a swift package reset-fingerprints command or similar.