Skip to content

Commit

Permalink
CLI: Add --mac-encrypted-only
Browse files Browse the repository at this point in the history
  • Loading branch information
gibbz00 committed Jan 5, 2024
1 parent c96da85 commit 36917f0
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 11 deletions.
11 changes: 9 additions & 2 deletions crates/cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::path::PathBuf;

use clap::{Args, Parser, Subcommand, ValueEnum, ValueHint};
use clap::{ArgAction, Args, Parser, Subcommand, ValueEnum, ValueHint};
use regex::Regex;
use rops::*;

Expand Down Expand Up @@ -29,6 +29,9 @@ pub struct EncryptArgs {
pub aws_kms_keys: Vec<<AwsKmsIntegration as Integration>::KeyId>,
#[command(flatten)]
pub partial_encryption_args: Option<PartialEncryptionArgs>,
/// Requires a partial encryption setting
#[arg(long, display_order = 11, requires = "partial_encryption", action(ArgAction::SetTrue))]
pub mac_only_encrypted: Option<bool>,
#[command(flatten)]
pub input_args: InputArgs,
}
Expand All @@ -44,14 +47,18 @@ pub struct InputArgs {
}

#[derive(Args)]
#[group(multiple = false)]
#[group(id = "partial_encryption", multiple = false)]
pub struct PartialEncryptionArgs {
/// Encrypt values matching key suffix.
#[arg(long, display_order = 10, value_name = "STRING")]
encrypted_suffix: Option<String>,
/// Encrypt values matching key regex.
#[arg(long, display_order = 10, value_name = "REGEX")]
encrypted_regex: Option<Regex>,
/// Skip encrypting values matching key suffix.
#[arg(long, display_order = 10, value_name = "STRING")]
unencrypted_suffix: Option<String>,
/// Skip encrypting values matching key regex.
#[arg(long, display_order = 10, value_name = "REGEX")]
unencrypted_regex: Option<Regex>,
}
Expand Down
4 changes: 4 additions & 0 deletions crates/cli/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ pub fn run() -> anyhow::Result<()> {
rops_file_builder = rops_file_builder.with_partial_encryption(partial_encryption_args.into())
}

if encrypt_args.mac_only_encrypted.unwrap_or_default() {
rops_file_builder = rops_file_builder.mac_only_encrypted()
}

let encrypted_rops_file = rops_file_builder.encrypt::<DefaultCipher, DefaultHasher>()?;
println!("{}", encrypted_rops_file);

Expand Down
33 changes: 24 additions & 9 deletions crates/cli/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,22 @@ fn encrypts_from_file() {

#[test]
fn encrypts_with_partial_encryption() {
let mut cmd = Command::package_command().encrypt();
cmd.arg(format!("--unencrypted-suffix={}", PartialEncryptionConfig::mock_display()));

let plaintext = sops_yaml_str!("age_unencrypted_suffix_plaintext");
let output = cmd.run_piped(plaintext);
output.assert_success();

let output = Command::package_command().encrypt().partial_encryption().run_piped(plaintext);
let decrypted_file = decrypt_output::<AgeIntegration>(output);
assert_eq!(Some(PartialEncryptionConfig::mock()), decrypted_file.metadata().partial_encryption)
}

#[test]
fn encrypts_with_mac_encrypted_only() {
let mut cmd = Command::package_command().encrypt().partial_encryption();
cmd.arg("--mac-only-encrypted");

let plaintext = sops_yaml_str!("age_mac_only_encrypted_plaintext");
let decrypted_file = decrypt_output::<AgeIntegration>(cmd.run_piped(plaintext));
assert_eq!(Some(true), decrypted_file.metadata().mac_only_encrypted)
}

#[test]
fn decrypts_from_stdin() {
let encrypted_str = sops_yaml_str!("age_example");
Expand All @@ -68,24 +73,34 @@ fn decrypts_from_file() {
assert_decrypted_output(cmd.run_tty())
}

#[rustfmt::skip]
trait EncryptCommand { fn encrypt(self) -> Self; }
trait EncryptCommand {
fn encrypt(self) -> Self;

fn partial_encryption(self) -> Self;
}
impl EncryptCommand for Command {
fn encrypt(mut self) -> Self {
self.arg("encrypt");
self.args(["--age", &<AgeIntegration as Integration>::KeyId::mock_display()]);
self.common_args()
}

fn partial_encryption(mut self) -> Self {
self.arg(format!("--unencrypted-suffix={}", PartialEncryptionConfig::mock_display()));
self
}
}

fn assert_encrypted<I: IntegrationTestUtils>(encrypted_output: Output, plaintext: &str) {
encrypted_output.assert_success();
let decrypted_file = decrypt_output::<I>(encrypted_output);
pretty_assertions::assert_eq!(plaintext, decrypted_file.map().to_string());
}

fn decrypt_output<I: IntegrationTestUtils>(encrypted_output: Output) -> RopsFile<DecryptedFile<DefaultHasher>, YamlFileFormat> {
encrypted_output.assert_success();

I::set_mock_private_key_env_var();

encrypted_output
.stdout_str()
.parse::<RopsFile<EncryptedFile<DefaultCipher, DefaultHasher>, YamlFileFormat>>()
Expand Down

0 comments on commit 36917f0

Please sign in to comment.