1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import struct Foundation.URL
import Basics
import _Concurrency
import Dispatch
import PackageModel
import struct TSCUtility.Version
public protocol PackageSigningEntityStorage {
/// For a given package, return the signing entities and the package versions that each of them signed.
func get(
package: PackageIdentity,
observabilityScope: ObservabilityScope
) throws -> PackageSigners
/// Record signer for a given package version.
///
/// This throws `PackageSigningEntityStorageError.conflict` if `signingEntity`
/// of the package version is different from that in storage.
func put(
package: PackageIdentity,
version: Version,
signingEntity: SigningEntity,
origin: SigningEntity.Origin,
observabilityScope: ObservabilityScope
) throws
/// Add signer for a given package version.
///
/// If the package version already has other `SigningEntity`s in storage, this
/// API **adds** `signingEntity` to the package version's signers rather than
/// throwing an error.
func add(
package: PackageIdentity,
version: Version,
signingEntity: SigningEntity,
origin: SigningEntity.Origin,
observabilityScope: ObservabilityScope
) throws
/// Make `signingEntity` the package's expected signer starting from the given version.
func changeSigningEntityFromVersion(
package: PackageIdentity,
version: Version,
signingEntity: SigningEntity,
origin: SigningEntity.Origin,
observabilityScope: ObservabilityScope
) throws
/// Make `signingEntity` the only signer for a given package.
///
/// This API deletes all other existing signers from storage, therefore making
/// `signingEntity` the package's sole signer.
func changeSigningEntityForAllVersions(
package: PackageIdentity,
version: Version,
signingEntity: SigningEntity,
origin: SigningEntity.Origin,
observabilityScope: ObservabilityScope
) throws
}
// MARK: - Models
extension SigningEntity {
public enum Origin: Hashable, Codable, CustomStringConvertible {
case registry(URL)
public var url: URL {
switch self {
case .registry(let url):
return url
}
}
public var description: String {
switch self {
case .registry(let url):
return "registry(\(url))"
}
}
}
}
public struct PackageSigner: Codable {
public let signingEntity: SigningEntity
public internal(set) var origins: Set<SigningEntity.Origin>
public internal(set) var versions: Set<Version>
public init(
signingEntity: SigningEntity,
origins: Set<SigningEntity.Origin>,
versions: Set<Version>
) {
self.signingEntity = signingEntity
self.origins = origins
self.versions = versions
}
}
public struct PackageSigners {
public internal(set) var expectedSigner: (signingEntity: SigningEntity, fromVersion: Version)?
public internal(set) var signers: [SigningEntity: PackageSigner]
public init(
expectedSigner: (signingEntity: SigningEntity, fromVersion: Version)? = .none,
signers: [SigningEntity: PackageSigner] = [:]
) {
self.expectedSigner = expectedSigner
self.signers = signers
}
public var isEmpty: Bool {
self.signers.isEmpty
}
public var versionSigningEntities: [Version: Set<SigningEntity>] {
var versionSigningEntities = [Version: Set<SigningEntity>]()
for (signingEntity, versions) in self.signers.map({ ($0.key, $0.value.versions) }) {
versions.forEach { version in
var signingEntities: Set<SigningEntity> = versionSigningEntities.removeValue(forKey: version) ?? []
signingEntities.insert(signingEntity)
versionSigningEntities[version] = signingEntities
}
}
return versionSigningEntities
}
public func signingEntities(of version: Version) -> Set<SigningEntity> {
Set(self.signers.values.filter { $0.versions.contains(version) }.map(\.signingEntity))
}
}
// MARK: - Errors
public enum PackageSigningEntityStorageError: Error, Equatable, CustomStringConvertible {
case conflict(package: PackageIdentity, version: Version, given: SigningEntity, existing: SigningEntity)
case unrecognizedSigningEntity(SigningEntity)
public var description: String {
switch self {
case .conflict(let package, let version, let given, let existing):
return "\(package) version \(version) was previously signed by '\(existing)', which is different from '\(given)'."
case .unrecognizedSigningEntity(let signingEntity):
return "'\(signingEntity)' is not recognized and therefore will not be saved."
}
}
}
public enum SigningEntityCheckingMode: String {
case strict
case warn
}
|