diff --git a/Sources/cctl/ImageCommand.swift b/Sources/cctl/ImageCommand.swift index c7e29bef..6247067b 100644 --- a/Sources/cctl/ImageCommand.swift +++ b/Sources/cctl/ImageCommand.swift @@ -105,7 +105,8 @@ extension Application { }) var unpackPath: String? - @Flag(help: "Pull via plain text http") var http: Bool = false + @Flag(help: "Pull anonymously via plain-text HTTP.") + var http: Bool = false func run() async throws { let imageStore = Application.imageStore @@ -124,7 +125,7 @@ extension Application { } var startTime = ContinuousClock.now - let image = try await Images.withAuthentication(ref: normalizedReference) { auth in + let image = try await Images.withAuthentication(ref: normalizedReference, insecure: http) { auth in try await imageStore.pull(reference: normalizedReference, platform: platform, insecure: http, auth: auth) } @@ -177,7 +178,8 @@ extension Application { @Option(help: "Platform string in the form 'os/arch/variant'. Example 'linux/arm64/v8', 'linux/amd64'") var platformString: String? - @Flag(help: "Push via plain text http") var http: Bool = false + @Flag(help: "Push anonymously via plain-text HTTP.") + var http: Bool = false @Argument var ref: String @@ -197,7 +199,7 @@ extension Application { print("Reference resolved to \(reference.description)") } - try await Images.withAuthentication(ref: normalizedReference) { auth in + try await Images.withAuthentication(ref: normalizedReference, insecure: http) { auth in try await imageStore.push(reference: normalizedReference, platform: platform, insecure: http, auth: auth) } print("image pushed") @@ -264,22 +266,26 @@ extension Application { } private static func withAuthentication( - ref: String, _ body: @Sendable @escaping (_ auth: Authentication?) async throws -> T? + ref: String, insecure: Bool, + _ body: @Sendable @escaping (_ auth: Authentication?) async throws -> T? ) async throws -> T? { - var authentication: Authentication? - let ref = try Reference.parse(ref) - guard let host = ref.resolvedDomain else { + let parsed = try Reference.parse(ref) + guard let host = parsed.resolvedDomain else { throw ContainerizationError(.invalidArgument, message: "no host specified in image reference") } - authentication = Self.authenticationFromEnv(host: host) - if let authentication { - return try await body(authentication) + if insecure { + return try await body(nil) + } + if let auth = Self.authenticationFromEnv(host: host) { + return try await body(auth) } #if os(macOS) let keychain = KeychainHelper(securityDomain: Application.keychainID) - authentication = try? keychain.lookup(hostname: host) - #endif + let authentication = try? keychain.lookup(hostname: host) return try await body(authentication) + #else + return try await body(nil) + #endif } private static func authenticationFromEnv(host: String) -> Authentication? { diff --git a/Sources/cctl/LoginCommand.swift b/Sources/cctl/LoginCommand.swift index 8389a6d4..d48311ef 100644 --- a/Sources/cctl/LoginCommand.swift +++ b/Sources/cctl/LoginCommand.swift @@ -41,8 +41,6 @@ extension Application { @Argument(help: "Registry server name") var server: String - @Flag(help: "Use plain text http to authenticate") var http: Bool = false - func run() async throws { var username = self.username var password = "" @@ -65,10 +63,9 @@ extension Application { } let server = Reference.resolveDomain(domain: self.server) - let scheme = http ? "http" : "https" let client = RegistryClient( host: server, - scheme: scheme, + scheme: "https", authentication: BasicAuthentication(username: username, password: password), retryOptions: .init( maxRetries: 10,