diff --git a/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md b/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md index bf3dd8c6..1f103865 100644 --- a/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md +++ b/Documentation/SwiftlyDocs.docc/swiftly-cli-reference.md @@ -456,7 +456,7 @@ written to this file as commands that can be run after the installation. Perform swiftly initialization into your user account. ``` -swiftly init [--no-modify-profile] [--overwrite] [--platform=] [--skip-install] [--quiet-shell-followup] [--assume-yes] [--verbose] [--version] [--help] +swiftly init [--no-modify-profile] [--overwrite] [--platform=] [--skip-install] [--quiet-shell-followup] [--verify] [--no-verify] [--assume-yes] [--verbose] [--version] [--help] ``` **--no-modify-profile:** @@ -484,6 +484,16 @@ swiftly init [--no-modify-profile] [--overwrite] [--platform=] [--skip *Quiet shell follow up commands* +**--verify:** + +*Verify (or not) the PGP signature of the toolchain that is installed during initialization.* + + +**--no-verify:** + +*Verify (or not) the PGP signature of the toolchain that is installed during initialization.* + + **--assume-yes:** *Disable confirmation prompts by assuming 'yes'* diff --git a/Sources/Swiftly/Init.swift b/Sources/Swiftly/Init.swift index 8d7212f6..959acb45 100644 --- a/Sources/Swiftly/Init.swift +++ b/Sources/Swiftly/Init.swift @@ -46,11 +46,16 @@ struct Init: SwiftlyCommand { var skipInstall: Bool = false @Flag(help: "Quiet shell follow up commands") var quietShellFollowup: Bool = false + @Flag( + inversion: .prefixedNo, + help: "Verify (or not) the PGP signature of the toolchain that is installed during initialization." + ) + var verify = true @OptionGroup var root: GlobalOptions private enum CodingKeys: String, CodingKey { - case noModifyProfile, overwrite, platform, skipInstall, root, quietShellFollowup + case noModifyProfile, overwrite, platform, skipInstall, root, quietShellFollowup, verify } public mutating func validate() throws {} @@ -60,11 +65,11 @@ struct Init: SwiftlyCommand { } mutating func run(_ ctx: SwiftlyCoreContext = Swiftly.createDefaultContext()) async throws { - try await Self.execute(ctx, assumeYes: self.root.assumeYes, noModifyProfile: self.noModifyProfile, overwrite: self.overwrite, platform: self.platform, verbose: self.root.verbose, skipInstall: self.skipInstall, quietShellFollowup: self.quietShellFollowup) + try await Self.execute(ctx, assumeYes: self.root.assumeYes, noModifyProfile: self.noModifyProfile, overwrite: self.overwrite, platform: self.platform, verbose: self.root.verbose, skipInstall: self.skipInstall, quietShellFollowup: self.quietShellFollowup, verifySignature: self.verify) } /// Initialize the installation of swiftly. - static func execute(_ ctx: SwiftlyCoreContext, assumeYes: Bool, noModifyProfile: Bool, overwrite: Bool, platform: String?, verbose: Bool, skipInstall: Bool, quietShellFollowup: Bool) async throws { + static func execute(_ ctx: SwiftlyCoreContext, assumeYes: Bool, noModifyProfile: Bool, overwrite: Bool, platform: String?, verbose: Bool, skipInstall: Bool, quietShellFollowup: Bool, verifySignature: Bool = true) async throws { try await Swiftly.currentPlatform.verifySwiftlySystemPrerequisites() var config = try? await Config.load(ctx) @@ -197,11 +202,15 @@ struct Init: SwiftlyCommand { suppressed with the '--skip-install' option. """ #if os(Linux) - msg += """ - In the process, swiftly will add swift.org - GnuPG keys into your keychain to verify the integrity of the downloads. + if verifySignature { + msg += """ + In the process, swiftly will add swift.org + GnuPG keys into your keychain to verify the integrity of the downloads. - """ + """ + } else { + msg += "\n" + } #else msg += "\n" #endif @@ -372,7 +381,7 @@ struct Init: SwiftlyCommand { } if let installVersion { - (postInstall, pathChanged) = try await Install.execute(ctx, version: installVersion, &config, useInstalledToolchain: true, verifySignature: true, verbose: verbose, assumeYes: assumeYes) + (postInstall, pathChanged) = try await Install.execute(ctx, version: installVersion, &config, useInstalledToolchain: true, verifySignature: verifySignature, verbose: verbose, assumeYes: assumeYes) } } diff --git a/Tests/SwiftlyTests/InitTests.swift b/Tests/SwiftlyTests/InitTests.swift index cdb3e8b6..a70cc599 100644 --- a/Tests/SwiftlyTests/InitTests.swift +++ b/Tests/SwiftlyTests/InitTests.swift @@ -1,3 +1,4 @@ +import ArgumentParser import Foundation @testable import Swiftly @testable import SwiftlyCore @@ -68,6 +69,19 @@ import Testing } } + @Test func initAcceptsNoVerify() throws { + // GIVEN: the gpg prerequisite check tells users to pass --no-verify + // WHEN: swiftly init is parsed with that flag + let noVerify = try Init.parse(["--no-verify"]) + + // THEN: it is accepted and signature verification is turned off + #expect(!noVerify.verify) + + // AND: verification stays on by default + #expect(try Init.parse([]).verify) + #expect(try Init.parse(["--verify"]).verify) + } + @Test(.testHome()) func initOverwrite() async throws { // GIVEN: a user account with swiftly already installed try? await fs.remove(atPath: Swiftly.currentPlatform.swiftlyConfigFile(SwiftlyTests.ctx))