feat: Working encrypt and decrypt commands.

This commit is contained in:
2024-11-30 19:27:18 -05:00
parent 81925a95d6
commit 56a406b231
7 changed files with 87 additions and 26 deletions

View File

@@ -68,13 +68,14 @@ extension CliClient: DependencyKey {
in: nil, in: nil,
args args
)) ))
} else {
try await shellClient.background(.init(
shell: shell,
environment: ProcessInfo.processInfo.environment,
in: nil,
args
))
} }
try await shellClient.background(.init(
shell: shell,
environment: ProcessInfo.processInfo.environment,
in: nil,
args
))
} createConfiguration: { path, json in } createConfiguration: { path, json in
// Early out if a file exists at the path already. // Early out if a file exists at the path already.

View File

@@ -12,6 +12,7 @@ public struct Configuration: Codable, Sendable {
public let templateDir: String? public let templateDir: String?
public let defaultPlaybookArgs: [String]? public let defaultPlaybookArgs: [String]?
public let defaultVaultArgs: [String]? public let defaultVaultArgs: [String]?
public let defaultVaultEncryptId: String?
fileprivate enum CodingKeys: String, CodingKey { fileprivate enum CodingKeys: String, CodingKey {
case playbookDir = "HPA_PLAYBOOK_DIR" case playbookDir = "HPA_PLAYBOOK_DIR"
@@ -21,6 +22,7 @@ public struct Configuration: Codable, Sendable {
case templateDir = "HPA_TEMPLATE_DIR" case templateDir = "HPA_TEMPLATE_DIR"
case defaultPlaybookArgs = "HPA_DEFAULT_PLAYBOOK_ARGS" case defaultPlaybookArgs = "HPA_DEFAULT_PLAYBOOK_ARGS"
case defaultVaultArgs = "HPA_DEFAULT_VAULT_ARGS" case defaultVaultArgs = "HPA_DEFAULT_VAULT_ARGS"
case defaultVaultEncryptId = "HPA_DEFAULT_VAULT_ENCRYPT_ID"
} }
public static func fromEnv( public static func fromEnv(
@@ -40,7 +42,8 @@ public struct Configuration: Codable, Sendable {
templateRepoVersion: hpaValues.value(for: .templateRepoVersion), templateRepoVersion: hpaValues.value(for: .templateRepoVersion),
templateDir: hpaValues.value(for: .templateDir), templateDir: hpaValues.value(for: .templateDir),
defaultPlaybookArgs: hpaValues.array(for: .defaultPlaybookArgs), defaultPlaybookArgs: hpaValues.array(for: .defaultPlaybookArgs),
defaultVaultArgs: hpaValues.array(for: .defaultVaultArgs) defaultVaultArgs: hpaValues.array(for: .defaultVaultArgs),
defaultVaultEncryptId: hpaValues.value(for: .defaultVaultEncryptId)
) )
} }
@@ -52,7 +55,8 @@ public struct Configuration: Codable, Sendable {
templateRepoVersion: "main", templateRepoVersion: "main",
templateDir: "/path/to/local/template", templateDir: "/path/to/local/template",
defaultPlaybookArgs: ["--tags", "debug"], defaultPlaybookArgs: ["--tags", "debug"],
defaultVaultArgs: ["--vault-id=myId@$SCRIPTS/vault-gopass-client"] defaultVaultArgs: ["--vault-id=myId@$SCRIPTS/vault-gopass-client"],
defaultVaultEncryptId: "myId"
) )
} }

View File

@@ -3,6 +3,19 @@ import Rainbow
extension CommandConfiguration { extension CommandConfiguration {
static func create(
commandName: String,
abstract: String,
usesExtraArgs: Bool = true,
discussion: Discussion
) -> Self {
.init(
commandName: commandName,
abstract: createAbstract(abstract),
discussion: discussion.render()
)
}
static func create( static func create(
commandName: String, commandName: String,
abstract: String, abstract: String,
@@ -25,12 +38,12 @@ extension CommandConfiguration {
.create( .create(
commandName: commandName, commandName: commandName,
abstract: abstract, abstract: abstract,
discussion: [.note(label: "Most options are not required if you have a configuration file setup.")] discussion: .default(
+ examples.nodes(parentCommand) usesExtraArgs: true,
+ [ parentCommand: parentCommand,
.seeAlso(label: "Ansible playbook options.", command: "ansible-playbook"), examples: examples,
.important(label: Constants.importantExtraArgsNote) seeAlso: .seeAlso(label: "Ansible playbook options.", command: "ansible-playbook")
] )
) )
} }
} }
@@ -42,6 +55,21 @@ func createAbstract(_ string: String) -> String {
struct Discussion { struct Discussion {
let nodes: [Node] let nodes: [Node]
static func `default`(
usesExtraArgs: Bool,
parentCommand: String?,
examples: [(label: String, example: String)],
seeAlso: Node?
) -> Self {
var nodes = Array.defaultNodes + examples.nodes(parentCommand)
if let seeAlso { nodes.append(seeAlso) }
if usesExtraArgs && examples.count > 0 { nodes.append(.important(label: Constants.importantExtraArgsNote)) }
return .init(
nodes: nodes,
usesExtraArgs: usesExtraArgs
)
}
init(usesExtraArgs: Bool = true, _ nodes: Node...) { init(usesExtraArgs: Bool = true, _ nodes: Node...) {
self.init(nodes: nodes, usesExtraArgs: usesExtraArgs) self.init(nodes: nodes, usesExtraArgs: usesExtraArgs)
} }
@@ -225,9 +253,13 @@ private extension Array where Element == (label: String, example: String) {
} }
} }
private extension Array where Element == Node { extension Array where Element == Node {
func render(separator: String = "\n\n") -> String { static var defaultNodes: Self {
[.note(label: "Most options are not required if you have a configuration file setup.")]
}
fileprivate func render(separator: String = "\n\n") -> String {
map { map {
// Strip of any new-line characters from the last section of the rendered string // Strip of any new-line characters from the last section of the rendered string
// of the node. This allows us to have a consistent single new-line between each // of the node. This allows us to have a consistent single new-line between each

View File

@@ -5,7 +5,7 @@ extension Logger.Level {
/// Set the log level based on the user's options supplied. /// Set the log level based on the user's options supplied.
init(globals: BasicGlobalOptions, quietOnlyPlaybook: Bool) { init(globals: BasicGlobalOptions, quietOnlyPlaybook: Bool) {
if quietOnlyPlaybook || !globals.quiet { if !quietOnlyPlaybook && !globals.quiet {
switch globals.verbose { switch globals.verbose {
case 0: case 0:
self = .info self = .info
@@ -16,6 +16,7 @@ extension Logger.Level {
default: default:
self = .info self = .info
} }
return
} }
self = .info self = .info
} }

View File

@@ -26,16 +26,23 @@ func runVault(
let defaultArgs = configuration.defaultVaultArgs ?? [] let defaultArgs = configuration.defaultVaultArgs ?? []
var vaultArgs = ["ansible-vault"]
+ args
+ defaultArgs
+ options.extraArgs
+ [path]
if args.contains("encrypt"),
!vaultArgs.contains("--encrypt-vault-id"),
let id = configuration.defaultVaultEncryptId
{
vaultArgs.append(contentsOf: ["--encrypt-vault-id", id])
}
try await cliClient.runCommand( try await cliClient.runCommand(
quiet: options.quiet, quiet: options.quiet,
shell: options.shellOrDefault, shell: options.shellOrDefault,
["ansible-vault"] vaultArgs
+ args
+ defaultArgs
+ options.extraArgs
+ [path]
) )
fatalError()
} }
} }

View File

@@ -18,6 +18,14 @@ struct DecryptCommand: AsyncParsableCommand {
var output: String? var output: String?
mutating func run() async throws { mutating func run() async throws {
fatalError() var args = ["decrypt"]
if let output {
args.append(contentsOf: ["--output", output])
}
try await runVault(
commandName: Self.commandName,
options: options,
args
)
} }
} }

View File

@@ -18,6 +18,14 @@ struct EncryptCommand: AsyncParsableCommand {
var output: String? var output: String?
mutating func run() async throws { mutating func run() async throws {
fatalError() var args = ["encrypt"]
if let output {
args.append(contentsOf: ["--output", output])
}
try await runVault(
commandName: Self.commandName,
options: options,
args
)
} }
} }