@@ -49,17 +49,17 @@ struct PackageSigningEntityTOFU {
49
49
) { result in
50
50
switch result {
51
51
case . success( let signerVersions) :
52
- self . isSigningEntityOK (
52
+ self . validateSigningEntity (
53
53
package : package ,
54
54
version: version,
55
55
signingEntity: signingEntity,
56
56
signerVersions: signerVersions,
57
57
observabilityScope: observabilityScope
58
- ) { isOKResult in
59
- switch isOKResult {
58
+ ) { validateResult in
59
+ switch validateResult {
60
60
case . success( let shouldWrite) :
61
61
// We only use certain type(s) of signing entity for TOFU
62
- guard shouldWrite, let signingEntity = signingEntity, signingEntity. type != nil else {
62
+ guard shouldWrite, let signingEntity = signingEntity, signingEntity. isRecognized else {
63
63
return completion ( . success( ( ) ) )
64
64
}
65
65
self . writeToStorage (
@@ -81,7 +81,7 @@ struct PackageSigningEntityTOFU {
81
81
}
82
82
}
83
83
84
- private func isSigningEntityOK (
84
+ private func validateSigningEntity (
85
85
package : PackageIdentity . RegistryIdentity ,
86
86
version: Version ,
87
87
signingEntity: SigningEntity ? ,
@@ -91,7 +91,7 @@ struct PackageSigningEntityTOFU {
91
91
) {
92
92
// Package is never signed.
93
93
// If signingEntity is nil, it means package remains unsigned, which is OK. (none -> none)
94
- // Otherwise, we are now assigning a signing entity, which is also OK. (none -> some)
94
+ // Otherwise, package has gained a signing entity, which is also OK. (none -> some)
95
95
if signerVersions. isEmpty {
96
96
return completion ( . success( true ) )
97
97
}
@@ -102,8 +102,10 @@ struct PackageSigningEntityTOFU {
102
102
// e.g., change of package ownership, package author decides to stop signing releases, etc.
103
103
// Instead of failing, we should allow and prompt user to add/replace/remove signing entity.
104
104
105
+ // We recorded the version's signer previously
105
106
if let signerForVersion = signerVersions. signingEntity ( of: version) {
106
- // We recorded a different signer for the given version before. This is NOT OK.
107
+ // The given signer is different
108
+ // TODO: This could indicate a legitimate change in package ownership
107
109
guard signerForVersion == signingEntity else {
108
110
return self . handleSigningEntityChanged (
109
111
package : package ,
@@ -115,11 +117,12 @@ struct PackageSigningEntityTOFU {
115
117
completion ( result. tryMap { false } )
116
118
}
117
119
}
118
- // Signer remains the same, which could be nil, for the version.
119
- completion ( . success( false ) )
120
+ // Signer remains the same for the version
121
+ return completion ( . success( false ) )
120
122
}
121
123
122
124
switch signingEntity {
125
+ // Is the package changing from one signer to another?
123
126
case . some( let signingEntity) :
124
127
// Check signer(s) of other version(s)
125
128
if let otherSigner = signerVersions. keys. filter ( { $0 != signingEntity } ) . first {
@@ -137,15 +140,29 @@ struct PackageSigningEntityTOFU {
137
140
// Package doesn't have any other signer besides the given one, which is good.
138
141
completion ( . success( true ) )
139
142
}
143
+ // Or is the package going from having a signer to .none?
140
144
case . none:
141
145
let versionSigners = signerVersions. versionSigners
142
- let sortedSignedVersions = Array ( versionSigners. keys) . sorted ( by: < )
143
- for signedVersion in sortedSignedVersions {
144
- // If the given version is semantically newer than any signed version,
145
- // then it must be signed. (i.e., when a package starts being signed
146
- // at a version, then all future versions must be signed.)
147
- // TODO: we might want to allow package becoming unsigned
148
- if version > signedVersion, let versionSigner = versionSigners [ signedVersion] {
146
+ // If the given version is semantically newer than any signed version,
147
+ // then it must be signed. (i.e., when a package starts being signed
148
+ // at a version, then all future versions must be signed.)
149
+ // TODO: We might want to allow package becoming unsigned
150
+ //
151
+ // Here we try to handle the scenario where there is more than
152
+ // one major version branch, and signing didn't start from the beginning
153
+ // for both of them. For example, suppose a project has 1.x and 2.x active
154
+ // major versions, and signing starts at 1.2.0 and 2.2.0. The first version
155
+ // that SwiftPM downloads is 1.5.0, which is signed and signer gets recorded.
156
+ // - When unsigned v1.1.0 is downloaded, we don't fail because it's
157
+ // an older version (i.e., < 1.5.0) and we allow it to be unsigned.
158
+ // - When unsigned v1.6.0 is downloaded, we fail because it's
159
+ // a newer version (i.e., < 1.5.0) and we assume it to be signed.
160
+ // - When unsigned v2.0.0 is downloaded, we don't fail because we haven't
161
+ // seen a signed 2.x release yet, so we assume 2.x releases are not signed.
162
+ let olderSignedVersions = versionSigners. keys. filter { $0. major == version. major && $0 < version }
163
+ . sorted ( by: > )
164
+ for signedVersion in olderSignedVersions {
165
+ if let versionSigner = versionSigners [ signedVersion] {
149
166
return self . handleSigningEntityChanged (
150
167
package : package ,
151
168
latest: signingEntity,
@@ -156,7 +173,7 @@ struct PackageSigningEntityTOFU {
156
173
}
157
174
}
158
175
}
159
- // Assume this is an older version before package started getting signed
176
+ // Assume the given version is an older version before package started getting signed
160
177
completion ( . success( false ) )
161
178
}
162
179
}
@@ -208,7 +225,7 @@ struct PackageSigningEntityTOFU {
208
225
) {
209
226
switch self . signingEntityCheckingMode {
210
227
case . strict:
211
- completion ( . failure( RegistryError . signingEntityForReleaseHasChanged (
228
+ completion ( . failure( RegistryError . signingEntityForReleaseChanged (
212
229
package : package . underlying,
213
230
version: version,
214
231
latest: latest,
@@ -232,10 +249,10 @@ struct PackageSigningEntityTOFU {
232
249
) {
233
250
switch self . signingEntityCheckingMode {
234
251
case . strict:
235
- completion ( . failure(
236
- RegistryError
237
- . signingEntityForPackageHasChanged ( package : package . underlying , latest: latest, previous: existing)
238
- ) )
252
+ completion ( . failure( RegistryError . signingEntityForPackageChanged (
253
+ package : package . underlying ,
254
+ latest: latest, previous: existing
255
+ ) ) )
239
256
case . warn:
240
257
observabilityScope
241
258
. emit (
0 commit comments