Skip to content

Commit e5b90ae

Browse files
authored
Add author and signer to package collection models (#6418)
Motivation: Package collection should have information about how a version was created. This includes the creator and signer. #6408 added `author` populated using GitHub data, but we can allow package collection author to specify version creator as well. rdar://106674475 Modifications: - Add `author` and `signer` to package collection models - Update `PackageSearchClient` to use more information from collection/index results
1 parent 2013fff commit e5b90ae

16 files changed

+258
-20
lines changed

Fixtures/Collections/JSON/good.json

+9
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@
6666
"name": "Apache-2.0",
6767
"url": "https://www.example.com/repos/RepoOne/LICENSE"
6868
},
69+
"author": {
70+
"name": "J. Appleseed"
71+
},
72+
"signer": {
73+
"type": "ADP",
74+
"commonName": "J. Appleseed",
75+
"organizationalUnitName": "A1",
76+
"organizationName": "Appleseed Inc."
77+
},
6978
"createdAt": "2020-10-21T09:25:36Z"
7079
}
7180
]

Fixtures/Collections/JSON/good_signed.json

+9
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@
6666
"name": "Apache-2.0",
6767
"url": "https://www.example.com/repos/RepoOne/LICENSE"
6868
},
69+
"author": {
70+
"name": "J. Appleseed"
71+
},
72+
"signer": {
73+
"type": "ADP",
74+
"commonName": "J. Appleseed",
75+
"organizationalUnitName": "A1",
76+
"organizationName": "Appleseed Inc."
77+
},
6978
"createdAt": "2020-10-21T09:25:36Z"
7079
}
7180
]

Package.swift

+1
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ let package = Package(
370370
"PackageCollections",
371371
"PackageModel",
372372
"PackageRegistry",
373+
"PackageSigning",
373374
]
374375
),
375376

Sources/PackageCollections/Model/PackageTypes.swift

+35
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ extension PackageCollectionsModel.Package {
143143

144144
/// The package version's author
145145
public let author: PackageCollectionsModel.Package.Author?
146+
147+
/// The package version's signer
148+
public let signer: PackageCollectionsModel.Signer?
146149

147150
/// When the package version was created
148151
public let createdAt: Date?
@@ -224,6 +227,38 @@ extension PackageCollectionsModel.Package {
224227
}
225228
}
226229

230+
extension PackageCollectionsModel {
231+
public struct Signer: Equatable, Codable {
232+
/// The signer type.
233+
public let type: SignerType
234+
235+
/// The common name of the signing certificate's subject.
236+
public let commonName: String
237+
238+
/// The organizational unit name of the signing certificate's subject.
239+
public let organizationalUnitName: String
240+
241+
/// The organization name of the signing certificate's subject.
242+
public let organizationName: String
243+
244+
public init(
245+
type: SignerType,
246+
commonName: String,
247+
organizationalUnitName: String,
248+
organizationName: String
249+
) {
250+
self.type = type
251+
self.commonName = commonName
252+
self.organizationalUnitName = organizationalUnitName
253+
self.organizationName = organizationName
254+
}
255+
}
256+
257+
public enum SignerType: String, Codable {
258+
case adp // Apple Developer Program
259+
}
260+
}
261+
227262
extension PackageCollectionsModel {
228263
public typealias PackageMetadata = (package: PackageCollectionsModel.Package, collections: [PackageCollectionsModel.CollectionIdentifier], provider: PackageMetadataProviderContext?)
229264
}

Sources/PackageCollections/PackageCollections.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,8 @@ public struct PackageCollections: PackageCollectionsProtocol, Closable {
657657
defaultToolsVersion: packageVersion.defaultToolsVersion,
658658
verifiedCompatibility: packageVersion.verifiedCompatibility,
659659
license: packageVersion.license,
660-
author: versionMetadata?.author,
660+
author: versionMetadata?.author ?? packageVersion.author,
661+
signer: packageVersion.signer,
661662
createdAt: versionMetadata?.createdAt ?? packageVersion.createdAt)
662663
}
663664
versions.sort(by: >)

Sources/PackageCollections/Providers/JSONPackageCollectionProvider.swift

+14-1
Original file line numberDiff line numberDiff line change
@@ -251,14 +251,27 @@ struct JSONPackageCollectionProvider: PackageCollectionProvider {
251251
}
252252
let license = version.license.flatMap { Model.License(from: $0) }
253253

254+
let signer: Model.Signer?
255+
if let versionSigner = version.signer, let signerType = Model.SignerType(rawValue: versionSigner.type.lowercased()) {
256+
signer = .init(
257+
type: signerType,
258+
commonName: versionSigner.commonName,
259+
organizationalUnitName: versionSigner.organizationalUnitName,
260+
organizationName: versionSigner.organizationName
261+
)
262+
} else {
263+
signer = nil
264+
}
265+
254266
return .init(version: parsedVersion,
255267
title: nil,
256268
summary: version.summary,
257269
manifests: manifests,
258270
defaultToolsVersion: defaultToolsVersion,
259271
verifiedCompatibility: verifiedCompatibility,
260272
license: license,
261-
author: nil,
273+
author: version.author.map { .init(username: $0.name, url: nil, service: nil) },
274+
signer: signer,
262275
createdAt: version.createdAt)
263276
}
264277
if versions.count != package.versions.count {

Sources/PackageCollectionsModel/Formats/v1.md

+7
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ A version object has metadata extracted from `Package.swift` and optionally addi
100100
* `license`: The package version's license. **Optional.**
101101
* `url`: The URL of the license file.
102102
* `name`: License name. [SPDX identifier](https://spdx.org/licenses/) (e.g., `Apache-2.0`, `MIT`, etc.) preferred. Omit if unknown. **Optional.**
103+
* `author`: The package version's author. **Optional.**
104+
* `name`: The author of the package version.
105+
* `signer`: The signer of the package version. **Optional.** Refer to [documentation](https://github.com/apple/swift-package-manager/blob/main/Documentation/PackageRegistryUsage.md#package-signing) on package signing for details.
106+
* `type`: The signer type. Currently the only valid value is `ADP` (Apple Developer Program).
107+
* `commonName`: The common name of the signing certificate's subject.
108+
* `organizationalUnitName`: The organizational unit name of the signing certificate's subject.
109+
* `organizationName`: The organization name of the signing certificate's subject.
103110
* `createdAt`: The ISO 8601-formatted datetime string when the package version was created. **Optional.**
104111

105112
##### Version-specific manifests

Sources/PackageCollectionsModel/PackageCollectionModel+v1.swift

+46
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ extension PackageCollectionModel.V1.Collection.Package {
141141
/// The package version's license.
142142
public let license: PackageCollectionModel.V1.License?
143143

144+
/// The author of the package version.
145+
public let author: Author?
146+
147+
/// The signer of the package version.
148+
public let signer: PackageCollectionModel.V1.Signer?
149+
144150
/// When the package version was created.
145151
public let createdAt: Date?
146152

@@ -152,6 +158,8 @@ extension PackageCollectionModel.V1.Collection.Package {
152158
defaultToolsVersion: String,
153159
verifiedCompatibility: [PackageCollectionModel.V1.Compatibility]?,
154160
license: PackageCollectionModel.V1.License?,
161+
author: Author?,
162+
signer: PackageCollectionModel.V1.Signer?,
155163
createdAt: Date?
156164
) {
157165
self.version = version
@@ -160,6 +168,8 @@ extension PackageCollectionModel.V1.Collection.Package {
160168
self.defaultToolsVersion = defaultToolsVersion
161169
self.verifiedCompatibility = verifiedCompatibility
162170
self.license = license
171+
self.author = author
172+
self.signer = signer
163173
self.createdAt = createdAt
164174
}
165175

@@ -194,6 +204,16 @@ extension PackageCollectionModel.V1.Collection.Package {
194204
self.minimumPlatformVersions = minimumPlatformVersions
195205
}
196206
}
207+
208+
public struct Author: Equatable, Codable {
209+
/// The author name.
210+
public let name: String
211+
212+
/// Creates an `Author`
213+
public init(name: String) {
214+
self.name = name
215+
}
216+
}
197217
}
198218
}
199219

@@ -286,6 +306,32 @@ extension PackageCollectionModel.V1 {
286306
self.url = url
287307
}
288308
}
309+
310+
public struct Signer: Equatable, Codable {
311+
/// The signer type. (e.g., ADP)
312+
public let type: String
313+
314+
/// The common name of the signing certificate's subject.
315+
public let commonName: String
316+
317+
/// The organizational unit name of the signing certificate's subject.
318+
public let organizationalUnitName: String
319+
320+
/// The organization name of the signing certificate's subject.
321+
public let organizationName: String
322+
323+
public init(
324+
type: String,
325+
commonName: String,
326+
organizationalUnitName: String,
327+
organizationName: String
328+
) {
329+
self.type = type
330+
self.commonName = commonName
331+
self.organizationalUnitName = organizationalUnitName
332+
self.organizationName = organizationName
333+
}
334+
}
289335
}
290336

291337
extension PackageCollectionModel.V1.Platform: Hashable {

Sources/PackageMetadata/PackageMetadata.swift

+54-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Dispatch
1515
import PackageCollections
1616
import PackageModel
1717
import PackageRegistry
18+
import PackageSigning
1819
import SourceControl
1920

2021
import struct Foundation.Date
@@ -72,6 +73,7 @@ public struct Package {
7273
public let author: Author?
7374
public let description: String?
7475
public let publishedAt: Date?
76+
public let signingEntity: SigningEntity?
7577
public let latestVersion: Version?
7678

7779
fileprivate init(
@@ -86,6 +88,7 @@ public struct Package {
8688
author: Author?,
8789
description: String?,
8890
publishedAt: Date?,
91+
signingEntity: SigningEntity?,
8992
latestVersion: Version? = nil,
9093
source: Source
9194
) {
@@ -100,6 +103,7 @@ public struct Package {
100103
self.author = author
101104
self.description = description
102105
self.publishedAt = publishedAt
106+
self.signingEntity = signingEntity
103107
self.latestVersion = latestVersion
104108
self.source = source
105109
}
@@ -150,6 +154,7 @@ public struct PackageSearchClient {
150154
public let author: Package.Author?
151155
public let description: String?
152156
public let publishedAt: Date?
157+
public let signingEntity: SigningEntity?
153158
}
154159

155160
private func getVersionMetadata(
@@ -172,7 +177,8 @@ public struct PackageSearchClient {
172177
resources: metadata.resources.map { .init($0) },
173178
author: metadata.author.map { .init($0) },
174179
description: metadata.description,
175-
publishedAt: metadata.publishedAt
180+
publishedAt: metadata.publishedAt,
181+
signingEntity: metadata.sourceArchive?.signingEntity
176182
)
177183
})
178184
}
@@ -189,18 +195,22 @@ public struct PackageSearchClient {
189195
self.indexAndCollections.findPackages(query) { result in
190196
do {
191197
let packages = try result.get().items.map {
192-
Package(
198+
let versions = $0.package.versions.sorted(by: >)
199+
let latestVersion = versions.first
200+
201+
return Package(
193202
identity: $0.package.identity,
194203
location: $0.package.location,
195204
versions: $0.package.versions.map(\.version),
196-
licenseURL: nil,
205+
licenseURL: $0.package.license?.url,
197206
readmeURL: $0.package.readmeURL,
198207
repositoryURLs: nil,
199208
resources: [],
200-
author: nil,
201-
description: nil,
202-
publishedAt: nil,
203-
latestVersion: nil,
209+
author: latestVersion?.author.map { .init($0) },
210+
description: latestVersion?.summary,
211+
publishedAt: latestVersion?.createdAt,
212+
signingEntity: latestVersion?.signer.map { SigningEntity(signer: $0) },
213+
latestVersion: latestVersion?.version,
204214
// this only makes sense in connection with providing versioned metadata
205215
source: .indexAndCollections(collections: $0.collections, indexes: $0.indexes)
206216
)
@@ -259,6 +269,7 @@ public struct PackageSearchClient {
259269
author: nil,
260270
description: nil,
261271
publishedAt: nil,
272+
signingEntity: nil,
262273
latestVersion: nil,
263274
// this only makes sense in connection with providing versioned metadata
264275
source: .sourceControl(url: url)
@@ -298,6 +309,7 @@ public struct PackageSearchClient {
298309
let author: Package.Author?
299310
let description: String?
300311
let publishedAt: Date?
312+
let signingEntity: SigningEntity?
301313
if case .success(let metadata) = result {
302314
licenseURL = metadata.licenseURL
303315
readmeURL = metadata.readmeURL
@@ -306,6 +318,7 @@ public struct PackageSearchClient {
306318
author = metadata.author
307319
description = metadata.description
308320
publishedAt = metadata.publishedAt
321+
signingEntity = metadata.signingEntity
309322
} else {
310323
licenseURL = nil
311324
readmeURL = self.guessReadMeURL(alternateLocations: metadata.alternateLocations)
@@ -314,6 +327,7 @@ public struct PackageSearchClient {
314327
author = nil
315328
description = nil
316329
publishedAt = nil
330+
signingEntity = nil
317331
}
318332

319333
return callback(.success([Package(
@@ -326,6 +340,7 @@ public struct PackageSearchClient {
326340
author: author,
327341
description: description,
328342
publishedAt: publishedAt,
343+
signingEntity: signingEntity,
329344
latestVersion: version,
330345
source: .registry(url: metadata.registry.url)
331346
)]))
@@ -342,6 +357,7 @@ public struct PackageSearchClient {
342357
author: nil,
343358
description: nil,
344359
publishedAt: nil,
360+
signingEntity: nil,
345361
latestVersion: nil,
346362
// this only makes sense in connection with providing versioned metadata
347363
source: .registry(url: metadata.registry.url)
@@ -426,6 +442,16 @@ extension Package.Author {
426442
url: author.url
427443
)
428444
}
445+
446+
fileprivate init(_ author: PackageCollectionsModel.Package.Author) {
447+
self.init(
448+
name: author.username,
449+
email: nil,
450+
description: nil,
451+
organization: nil,
452+
url: author.url
453+
)
454+
}
429455
}
430456

431457
extension Package.Organization {
@@ -438,3 +464,24 @@ extension Package.Organization {
438464
)
439465
}
440466
}
467+
468+
extension SigningEntity {
469+
fileprivate init(signer: PackageCollectionsModel.Signer) {
470+
// All package collection signers are "recognized"
471+
self = .recognized(
472+
type: .init(signer.type),
473+
name: signer.commonName,
474+
organizationalUnit: signer.organizationalUnitName,
475+
organization: signer.organizationName
476+
)
477+
}
478+
}
479+
480+
extension SigningEntityType {
481+
fileprivate init(_ type: PackageCollectionsModel.SignerType) {
482+
switch type {
483+
case .adp:
484+
self = .adp
485+
}
486+
}
487+
}

0 commit comments

Comments
 (0)