165 lines
3.8 KiB
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
|
|
}
|