mirror of https://github.com/cirruslabs/tart.git
Introduce "tart logout" command (#583)
* Introduce "tart logout" * tart login: introduce --no-validate
This commit is contained in:
parent
35f5b30bc4
commit
5eddd1ce41
|
|
@ -17,6 +17,9 @@ struct Login: AsyncParsableCommand {
|
|||
@Flag(help: "connect to the OCI registry via insecure HTTP protocol")
|
||||
var insecure: Bool = false
|
||||
|
||||
@Flag(help: "skip validation of the registry's credentials before logging-in")
|
||||
var noValidate: Bool = false
|
||||
|
||||
func validate() throws {
|
||||
let usernameProvided = username != nil
|
||||
let passwordProvided = passwordStdin
|
||||
|
|
@ -45,12 +48,14 @@ struct Login: AsyncParsableCommand {
|
|||
host: (user, password)
|
||||
])
|
||||
|
||||
do {
|
||||
let registry = try Registry(host: host, namespace: "", insecure: insecure,
|
||||
credentialsProviders: [credentialsProvider])
|
||||
try await registry.ping()
|
||||
} catch {
|
||||
throw RuntimeError.InvalidCredentials("invalid credentials: \(error)")
|
||||
if !noValidate {
|
||||
do {
|
||||
let registry = try Registry(host: host, namespace: "", insecure: insecure,
|
||||
credentialsProviders: [credentialsProvider])
|
||||
try await registry.ping()
|
||||
} catch {
|
||||
throw RuntimeError.InvalidCredentials("invalid credentials: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
try KeychainCredentialsProvider().store(host: host, user: user, password: password)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
import ArgumentParser
|
||||
import Dispatch
|
||||
import SwiftUI
|
||||
|
||||
struct Logout: AsyncParsableCommand {
|
||||
static var configuration = CommandConfiguration(abstract: "Logout from a registry")
|
||||
|
||||
@Argument(help: "host")
|
||||
var host: String
|
||||
|
||||
func run() async throws {
|
||||
try KeychainCredentialsProvider().remove(host: host)
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +61,24 @@ class KeychainCredentialsProvider: CredentialsProvider {
|
|||
throw CredentialsProviderError.Failed(message: "Keychain failed to find item: \(status.explanation())")
|
||||
}
|
||||
}
|
||||
|
||||
func remove(host: String) throws {
|
||||
let query: [String: Any] = [kSecClass as String: kSecClassInternetPassword,
|
||||
kSecAttrServer as String: host,
|
||||
kSecAttrLabel as String: "Tart Credentials",
|
||||
]
|
||||
|
||||
let status = SecItemDelete(query as CFDictionary)
|
||||
|
||||
switch status {
|
||||
case errSecSuccess:
|
||||
return
|
||||
case errSecItemNotFound:
|
||||
return
|
||||
default:
|
||||
throw CredentialsProviderError.Failed(message: "Failed to remove Keychain item(s): \(status.explanation())")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension OSStatus {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ struct Root: AsyncParsableCommand {
|
|||
Get.self,
|
||||
List.self,
|
||||
Login.self,
|
||||
Logout.self,
|
||||
IP.self,
|
||||
Pull.self,
|
||||
Push.self,
|
||||
|
|
|
|||
Loading…
Reference in New Issue