Files
swift-hpa/Sources/VaultClient/VaultClient.swift

165 lines
3.8 KiB
Swift

import CommandClient
import ConfigurationClient
import Dependencies
import DependenciesMacros
import FileClient
// TODO: Add edit / view routes, possibly create?
public extension DependencyValues {
var vaultClient: VaultClient {
get { self[VaultClient.self] }
set { self[VaultClient.self] = newValue }
}
}
@DependencyClient
public struct VaultClient: Sendable {
public var run: @Sendable (RunOptions) async throws -> Void
public struct RunOptions: Equatable, Sendable {
public let extraOptions: [String]?
public let loggingOptions: LoggingOptions
public let outputFilePath: String?
public let quiet: Bool
public let route: Route
public let shell: String?
public let vaultFilePath: String?
public init(
_ route: Route,
extraOptions: [String]? = nil,
loggingOptions: LoggingOptions,
outputFilePath: String? = nil,
quiet: Bool = false,
shell: String? = nil,
vaultFilePath: String? = nil
) {
self.extraOptions = extraOptions
self.loggingOptions = loggingOptions
self.outputFilePath = outputFilePath
self.quiet = quiet
self.route = route
self.shell = shell
self.vaultFilePath = vaultFilePath
}
public enum Route: String, Equatable, Sendable {
case encrypt
case decrypt
@_spi(Internal)
public var verb: String { rawValue }
}
}
}
extension VaultClient: DependencyKey {
public static let testValue: VaultClient = Self()
public static var liveValue: VaultClient {
.init(
run: { try await $0.run() }
)
}
}
@_spi(Internal)
public extension VaultClient {
enum Constants {
public static let vaultCommand = "ansible-vault"
}
}
extension VaultClient.RunOptions {
func run() async throws {
@Dependency(\.commandClient) var commandClient
try await commandClient.run(
logging: loggingOptions,
quiet: quiet,
shell: shell
) {
@Dependency(\.configurationClient) var configurationClient
@Dependency(\.fileClient) var fileClient
@Dependency(\.logger) var logger
let configuration = try await configurationClient.findAndLoad()
logger.trace("Configuration: \(configuration)")
var vaultFilePath: String? = vaultFilePath
if vaultFilePath == nil {
vaultFilePath = try await fileClient
.findVaultFileInCurrentDirectory()?
.cleanFilePath
}
guard let vaultFilePath else {
throw VaultClientError.vaultFileNotFound
}
logger.trace("Vault file: \(vaultFilePath)")
var arguments = [
VaultClient.Constants.vaultCommand,
route.verb
]
if let outputFilePath {
arguments.append(contentsOf: ["--output", outputFilePath])
}
if let extraOptions {
arguments.append(contentsOf: extraOptions)
}
if let vaultArgs = configuration.vault.args {
arguments.append(contentsOf: vaultArgs)
}
if arguments.contains("encrypt"),
!arguments.contains("--encrypt-vault-id"),
let id = configuration.vault.encryptId
{
arguments.append(contentsOf: ["--encrypt-vault-id", id])
}
arguments.append(vaultFilePath)
logger.trace("Arguments: \(arguments)")
return arguments
}
}
}
// extension VaultClient.RunOptions.Route {
//
// var arguments: [String] {
// let outputFile: String?
// var arguments: [String]
//
// switch self {
// case let .decrypt(outputFile: output):
// outputFile = output
// arguments = ["decrypt"]
// case let .encrypt(outputFile: output):
// outputFile = output
// arguments = ["encrypt"]
// }
//
// if let outputFile {
// arguments.append(contentsOf: ["--output", outputFile])
// }
// return arguments
// }
// }
enum VaultClientError: Error {
case vaultFileNotFound
}