From 662e656039c544c7dab5c187a69aff2810d8ddce Mon Sep 17 00:00:00 2001 From: Veinar Date: Mon, 9 Dec 2024 14:24:21 +0100 Subject: [PATCH 1/2] Added quiet flag for commands #10 --- envcloak/commands/compare.py | 7 +++++-- envcloak/commands/decrypt.py | 9 ++++++--- envcloak/commands/encrypt.py | 10 ++++++---- envcloak/commands/generate_key.py | 15 +++++++++----- .../commands/generate_key_from_password.py | 17 +++++++++++----- envcloak/commands/rotate_keys.py | 19 ++++++++++++------ envcloak/decorators/common_decorators.py | 11 ++++++++++ envcloak/generator.py | 8 ++++---- envcloak/utils.py | 20 ++++++++++++++++--- 9 files changed, 84 insertions(+), 32 deletions(-) diff --git a/envcloak/commands/compare.py b/envcloak/commands/compare.py index c116f78..c257e5b 100644 --- a/envcloak/commands/compare.py +++ b/envcloak/commands/compare.py @@ -7,8 +7,11 @@ import click from click import style from envcloak.comparator import compare_files_or_directories -from envcloak.utils import debug_log -from envcloak.decorators.common_decorators import debug_option, no_sha_validation_option +from envcloak.utils import debug_log, conditional_echo, conditional_secho +from envcloak.decorators.common_decorators import ( + debug_option, + no_sha_validation_option, +) @click.command() diff --git a/envcloak/commands/decrypt.py b/envcloak/commands/decrypt.py index 9325781..477b259 100644 --- a/envcloak/commands/decrypt.py +++ b/envcloak/commands/decrypt.py @@ -9,7 +9,7 @@ debug_log, calculate_required_space, list_files_to_encrypt, - read_key_file, + read_key_file, conditional_echo, conditional_secho ) from envcloak.handlers import ( handle_directory_preview, @@ -23,6 +23,7 @@ no_sha_validation_option, recursion_option, preview_option, + quiet_option, ) from envcloak.validation import ( check_file_exists, @@ -39,6 +40,7 @@ @click.command() @debug_option +@quiet_option @dry_run_option @force_option @no_sha_validation_option @@ -76,6 +78,7 @@ def decrypt( skip_sha_validation, recursion, preview, + quiet, ): """ Decrypt environment variables from a file or all files in a directory. @@ -129,7 +132,7 @@ def decrypt( debug, ) decrypt_file(input, output, key, validate_integrity=not skip_sha_validation) - click.echo(f"File {input} decrypted -> {output} using key {key_file}") + conditional_echo(f"File {input} decrypted -> {output} using key {key_file}", quiet) elif directory: debug_log(f"Debug: Decrypting files in directory {directory}.", debug) traverse_and_process_files( @@ -146,7 +149,7 @@ def decrypt( ), recursion=recursion, ) - click.echo(f"All files in directory {directory} decrypted -> {output}") + conditional_echo(f"All files in directory {directory} decrypted -> {output}", quiet) except FileDecryptionException as e: click.echo( f"Error during decryption: Error: Failed to decrypt the file.\nDetails: {e.details}", diff --git a/envcloak/commands/encrypt.py b/envcloak/commands/encrypt.py index c67b427..7964a58 100644 --- a/envcloak/commands/encrypt.py +++ b/envcloak/commands/encrypt.py @@ -10,7 +10,7 @@ calculate_required_space, list_files_to_encrypt, validate_paths, - read_key_file, + read_key_file, conditional_echo, conditional_secho ) from envcloak.handlers import ( handle_directory_preview, @@ -23,6 +23,7 @@ dry_run_option, recursion_option, preview_option, + quiet_option, ) from envcloak.validation import ( check_disk_space, @@ -34,6 +35,7 @@ @click.command() +@quiet_option @debug_option @dry_run_option @force_option @@ -58,7 +60,7 @@ "--key-file", "-k", required=True, help="Path to the encryption key file." ) def encrypt( - input, directory, output, key_file, dry_run, force, debug, recursion, preview + input, directory, output, key_file, dry_run, force, debug, recursion, preview, quiet ): """ Encrypt environment variables from a file or all files in a directory. @@ -106,7 +108,7 @@ def encrypt( debug, ) encrypt_file(input, output, key) - click.echo(f"File {input} encrypted -> {output} using key {key_file}") + conditional_echo(f"File {input} encrypted -> {output} using key {key_file}", quiet) elif directory: debug_log(f"Debug: Encrypting files in directory {directory}.", debug) traverse_and_process_files( @@ -120,7 +122,7 @@ def encrypt( ), recursion=recursion, ) - click.echo(f"All files in directory {directory} encrypted -> {output}") + conditional_echo(f"All files in directory {directory} encrypted -> {output}", quiet) except FileEncryptionException as e: click.echo( f"Error: An error occurred during file encryption.\nDetails: {e}", diff --git a/envcloak/commands/generate_key.py b/envcloak/commands/generate_key.py index 3d50104..f83af0b 100644 --- a/envcloak/commands/generate_key.py +++ b/envcloak/commands/generate_key.py @@ -8,13 +8,18 @@ import click from envcloak.validation import check_output_not_exists, check_disk_space from envcloak.generator import generate_key_file -from envcloak.utils import add_to_gitignore, debug_log -from envcloak.decorators.common_decorators import debug_option, dry_run_option +from envcloak.utils import add_to_gitignore, debug_log, conditional_echo, conditional_secho +from envcloak.decorators.common_decorators import ( + debug_option, + dry_run_option, + quiet_option, +) from envcloak.exceptions import OutputFileExistsException, DiskSpaceException @click.command() @debug_option +@quiet_option @dry_run_option @click.option( "--output", "-o", required=True, help="Path to save the generated encryption key." @@ -22,7 +27,7 @@ @click.option( "--no-gitignore", is_flag=True, help="Skip adding the key file to .gitignore." ) -def generate_key(output, no_gitignore, dry_run, debug): +def generate_key(output, no_gitignore, dry_run, debug, quiet): """ Generate a new encryption key. """ @@ -47,12 +52,12 @@ def generate_key(output, no_gitignore, dry_run, debug): # Actual key generation logic debug_log(f"Debug: Generating key file at {output}.", debug) output_path = Path(output) - generate_key_file(output_path) + generate_key_file(output_path, quiet) if not no_gitignore: debug_log( f"Debug: Adding {output_path.name} to .gitignore in parent directory {output_path.parent}.", debug, ) - add_to_gitignore(output_path.parent, output_path.name) + add_to_gitignore(output_path.parent, output_path.name, quiet) except (OutputFileExistsException, DiskSpaceException) as e: click.echo(f"Error during key generation: {str(e)}") diff --git a/envcloak/commands/generate_key_from_password.py b/envcloak/commands/generate_key_from_password.py index efcfbbe..b6f7ba0 100644 --- a/envcloak/commands/generate_key_from_password.py +++ b/envcloak/commands/generate_key_from_password.py @@ -8,8 +8,12 @@ import click from envcloak.validation import check_output_not_exists, check_disk_space, validate_salt from envcloak.generator import generate_key_from_password_file -from envcloak.utils import debug_log, add_to_gitignore -from envcloak.decorators.common_decorators import debug_option, dry_run_option +from envcloak.utils import debug_log, add_to_gitignore, conditional_echo, conditional_secho +from envcloak.decorators.common_decorators import ( + debug_option, + dry_run_option, + quiet_option, +) from envcloak.exceptions import ( OutputFileExistsException, DiskSpaceException, @@ -19,6 +23,7 @@ @click.command() @debug_option +@quiet_option @dry_run_option @click.option( "--password", "-p", required=True, help="Password to derive the encryption key." @@ -32,7 +37,9 @@ @click.option( "--no-gitignore", is_flag=True, help="Skip adding the key file to .gitignore." ) -def generate_key_from_password(password, salt, output, no_gitignore, dry_run, debug): +def generate_key_from_password( + password, salt, output, no_gitignore, dry_run, debug, quiet +): """ Derive an encryption key from a password and salt. """ @@ -58,12 +65,12 @@ def generate_key_from_password(password, salt, output, no_gitignore, dry_run, de # Actual key derivation logic debug_log(f"Debug: Deriving key from password for output file {output}.", debug) output_path = Path(output) - generate_key_from_password_file(password, output_path, salt) + generate_key_from_password_file(password, output_path, quiet, salt) if not no_gitignore: debug_log( f"Debug: Adding {output_path.name} to .gitignore in parent directory {output_path.parent}.", debug, ) - add_to_gitignore(output_path.parent, output_path.name) + add_to_gitignore(output_path.parent, output_path.name, quiet) except (OutputFileExistsException, DiskSpaceException, InvalidSaltException) as e: click.echo(f"Error during key derivation: {str(e)}") diff --git a/envcloak/commands/rotate_keys.py b/envcloak/commands/rotate_keys.py index e8c6214..315b147 100644 --- a/envcloak/commands/rotate_keys.py +++ b/envcloak/commands/rotate_keys.py @@ -6,8 +6,12 @@ import os import click -from envcloak.utils import debug_log -from envcloak.decorators.common_decorators import debug_option, dry_run_option +from envcloak.utils import debug_log, conditional_echo, conditional_secho +from envcloak.decorators.common_decorators import ( + debug_option, + dry_run_option, + quiet_option, +) from envcloak.validation import ( check_file_exists, check_permissions, @@ -25,6 +29,7 @@ @click.command() @debug_option +@quiet_option @dry_run_option @click.option( "--input", "-i", required=True, help="Path to the encrypted file to re-encrypt." @@ -41,7 +46,9 @@ is_flag=True, help="Preview the key rotation process without making changes.", ) -def rotate_keys(input, old_key_file, new_key_file, output, dry_run, debug, preview): +def rotate_keys( + input, old_key_file, new_key_file, output, dry_run, debug, preview, quiet +): """ Rotate encryption keys by re-encrypting a file with a new key. """ @@ -59,14 +66,14 @@ def rotate_keys(input, old_key_file, new_key_file, output, dry_run, debug, previ # Handle Preview or Dry-run modes if preview: - click.secho( + conditional_secho( f""" Preview of Key Rotation: - Old key: {old_key_file} will no longer be valid for this encrypted file. - New key: {new_key_file} will be used to decrypt the encrypted file. - Encrypted file: {input} will be re-encrypted to {output}. """, - fg="cyan", + fg="cyan", quiet=quiet ) return if dry_run: @@ -95,7 +102,7 @@ def rotate_keys(input, old_key_file, new_key_file, output, dry_run, debug, previ debug_log(f"Debug: Removing temporary decrypted file {temp_decrypted}.", debug) os.remove(temp_decrypted) # Clean up temporary file - click.echo(f"Keys rotated for {input} -> {output}") + conditional_echo(f"Keys rotated for {input} -> {output}", quiet) except ( OutputFileExistsException, DiskSpaceException, diff --git a/envcloak/decorators/common_decorators.py b/envcloak/decorators/common_decorators.py index 30f362e..5dbc35b 100644 --- a/envcloak/decorators/common_decorators.py +++ b/envcloak/decorators/common_decorators.py @@ -69,3 +69,14 @@ def preview_option(func): is_flag=True, help="List files that will be decrypted (only applicable for directories).", )(func) + + +def quiet_option(func): + """ + Add a `--quiet` flag to a Click command. + """ + return click.option( + "--quiet", + is_flag=True, + help="Suppress all output except errors.", + )(func) diff --git a/envcloak/generator.py b/envcloak/generator.py index fdeaf27..402c8e2 100644 --- a/envcloak/generator.py +++ b/envcloak/generator.py @@ -12,7 +12,7 @@ import secrets -def generate_key_file(output_path: Path): +def generate_key_file(output_path: Path, quiet: bool): """ Generate a secure random encryption key, save it to a file. """ @@ -20,10 +20,10 @@ def generate_key_file(output_path: Path): output_path.parent.mkdir(parents=True, exist_ok=True) # Ensure directory exists with open(output_path, "wb") as key_file: key_file.write(key) - print(f"Encryption key generated and saved to {output_path}") + if not quiet: print(f"Encryption key generated and saved to {output_path}") -def generate_key_from_password_file(password: str, output_path: Path, salt: str = None): +def generate_key_from_password_file(password: str, output_path: Path, quiet: bool, salt: str = None): """ Derive an encryption key from a password and save it to a file. If no salt is provided, a random one is generated. @@ -49,4 +49,4 @@ def generate_key_from_password_file(password: str, output_path: Path, salt: str with open(output_path, "wb") as key_file: key_file.write(key) - print(f"Derived encryption key saved to {output_path}") + if not quiet: print(f"Derived encryption key saved to {output_path}") diff --git a/envcloak/utils.py b/envcloak/utils.py index f971611..87975ea 100644 --- a/envcloak/utils.py +++ b/envcloak/utils.py @@ -17,7 +17,7 @@ ) -def add_to_gitignore(directory: str, filename: str): +def add_to_gitignore(directory: str, filename: str, quiet: bool): """ Add a filename to the .gitignore file in the specified directory. @@ -32,12 +32,12 @@ def add_to_gitignore(directory: str, filename: str): content = gitignore_file.read() if filename not in content: gitignore_file.write(f"\n{filename}") - print(f"Added '{filename}' to {gitignore_path}") + if not quiet: print(f"Added '{filename}' to {gitignore_path}") else: # Create a new .gitignore file and add the filename with open(gitignore_path, "w", encoding="utf-8") as gitignore_file: gitignore_file.write(f"{filename}\n") - print(f"Created {gitignore_path} and added '{filename}'") + if not quiet: print(f"Created {gitignore_path} and added '{filename}'") def calculate_required_space(input=None, directory=None): @@ -143,3 +143,17 @@ def read_key_file(key_file, debug): key = kf.read() debug_log(f"Debug: Key file {key_file} read successfully.", debug) return key + +def conditional_echo(message, quiet, **kwargs): + """ + Echo a message only if `quiet` is False. + """ + if not quiet: + click.echo(message, **kwargs) + +def conditional_secho(message, quiet, **kwargs): + """ + Styled echo a message only if `quiet` is False. + """ + if not quiet: + click.secho(message, **kwargs) \ No newline at end of file From 5358e6a758d50244513455c1a3d9fd640cff14ab Mon Sep 17 00:00:00 2001 From: Veinar Date: Mon, 9 Dec 2024 14:25:10 +0100 Subject: [PATCH 2/2] Black formatting applied --- envcloak/commands/decrypt.py | 12 +++++++++--- envcloak/commands/encrypt.py | 12 +++++++++--- envcloak/commands/generate_key.py | 7 ++++++- envcloak/commands/generate_key_from_password.py | 7 ++++++- envcloak/commands/rotate_keys.py | 3 ++- envcloak/generator.py | 10 +++++++--- envcloak/utils.py | 10 +++++++--- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/envcloak/commands/decrypt.py b/envcloak/commands/decrypt.py index 477b259..9e899fc 100644 --- a/envcloak/commands/decrypt.py +++ b/envcloak/commands/decrypt.py @@ -9,7 +9,9 @@ debug_log, calculate_required_space, list_files_to_encrypt, - read_key_file, conditional_echo, conditional_secho + read_key_file, + conditional_echo, + conditional_secho, ) from envcloak.handlers import ( handle_directory_preview, @@ -132,7 +134,9 @@ def decrypt( debug, ) decrypt_file(input, output, key, validate_integrity=not skip_sha_validation) - conditional_echo(f"File {input} decrypted -> {output} using key {key_file}", quiet) + conditional_echo( + f"File {input} decrypted -> {output} using key {key_file}", quiet + ) elif directory: debug_log(f"Debug: Decrypting files in directory {directory}.", debug) traverse_and_process_files( @@ -149,7 +153,9 @@ def decrypt( ), recursion=recursion, ) - conditional_echo(f"All files in directory {directory} decrypted -> {output}", quiet) + conditional_echo( + f"All files in directory {directory} decrypted -> {output}", quiet + ) except FileDecryptionException as e: click.echo( f"Error during decryption: Error: Failed to decrypt the file.\nDetails: {e.details}", diff --git a/envcloak/commands/encrypt.py b/envcloak/commands/encrypt.py index 7964a58..2f4056f 100644 --- a/envcloak/commands/encrypt.py +++ b/envcloak/commands/encrypt.py @@ -10,7 +10,9 @@ calculate_required_space, list_files_to_encrypt, validate_paths, - read_key_file, conditional_echo, conditional_secho + read_key_file, + conditional_echo, + conditional_secho, ) from envcloak.handlers import ( handle_directory_preview, @@ -108,7 +110,9 @@ def encrypt( debug, ) encrypt_file(input, output, key) - conditional_echo(f"File {input} encrypted -> {output} using key {key_file}", quiet) + conditional_echo( + f"File {input} encrypted -> {output} using key {key_file}", quiet + ) elif directory: debug_log(f"Debug: Encrypting files in directory {directory}.", debug) traverse_and_process_files( @@ -122,7 +126,9 @@ def encrypt( ), recursion=recursion, ) - conditional_echo(f"All files in directory {directory} encrypted -> {output}", quiet) + conditional_echo( + f"All files in directory {directory} encrypted -> {output}", quiet + ) except FileEncryptionException as e: click.echo( f"Error: An error occurred during file encryption.\nDetails: {e}", diff --git a/envcloak/commands/generate_key.py b/envcloak/commands/generate_key.py index f83af0b..9a067c0 100644 --- a/envcloak/commands/generate_key.py +++ b/envcloak/commands/generate_key.py @@ -8,7 +8,12 @@ import click from envcloak.validation import check_output_not_exists, check_disk_space from envcloak.generator import generate_key_file -from envcloak.utils import add_to_gitignore, debug_log, conditional_echo, conditional_secho +from envcloak.utils import ( + add_to_gitignore, + debug_log, + conditional_echo, + conditional_secho, +) from envcloak.decorators.common_decorators import ( debug_option, dry_run_option, diff --git a/envcloak/commands/generate_key_from_password.py b/envcloak/commands/generate_key_from_password.py index b6f7ba0..8dd168b 100644 --- a/envcloak/commands/generate_key_from_password.py +++ b/envcloak/commands/generate_key_from_password.py @@ -8,7 +8,12 @@ import click from envcloak.validation import check_output_not_exists, check_disk_space, validate_salt from envcloak.generator import generate_key_from_password_file -from envcloak.utils import debug_log, add_to_gitignore, conditional_echo, conditional_secho +from envcloak.utils import ( + debug_log, + add_to_gitignore, + conditional_echo, + conditional_secho, +) from envcloak.decorators.common_decorators import ( debug_option, dry_run_option, diff --git a/envcloak/commands/rotate_keys.py b/envcloak/commands/rotate_keys.py index 315b147..9963e0e 100644 --- a/envcloak/commands/rotate_keys.py +++ b/envcloak/commands/rotate_keys.py @@ -73,7 +73,8 @@ def rotate_keys( - New key: {new_key_file} will be used to decrypt the encrypted file. - Encrypted file: {input} will be re-encrypted to {output}. """, - fg="cyan", quiet=quiet + fg="cyan", + quiet=quiet, ) return if dry_run: diff --git a/envcloak/generator.py b/envcloak/generator.py index 402c8e2..71cdfbb 100644 --- a/envcloak/generator.py +++ b/envcloak/generator.py @@ -20,10 +20,13 @@ def generate_key_file(output_path: Path, quiet: bool): output_path.parent.mkdir(parents=True, exist_ok=True) # Ensure directory exists with open(output_path, "wb") as key_file: key_file.write(key) - if not quiet: print(f"Encryption key generated and saved to {output_path}") + if not quiet: + print(f"Encryption key generated and saved to {output_path}") -def generate_key_from_password_file(password: str, output_path: Path, quiet: bool, salt: str = None): +def generate_key_from_password_file( + password: str, output_path: Path, quiet: bool, salt: str = None +): """ Derive an encryption key from a password and save it to a file. If no salt is provided, a random one is generated. @@ -49,4 +52,5 @@ def generate_key_from_password_file(password: str, output_path: Path, quiet: boo with open(output_path, "wb") as key_file: key_file.write(key) - if not quiet: print(f"Derived encryption key saved to {output_path}") + if not quiet: + print(f"Derived encryption key saved to {output_path}") diff --git a/envcloak/utils.py b/envcloak/utils.py index 87975ea..fd7d200 100644 --- a/envcloak/utils.py +++ b/envcloak/utils.py @@ -32,12 +32,14 @@ def add_to_gitignore(directory: str, filename: str, quiet: bool): content = gitignore_file.read() if filename not in content: gitignore_file.write(f"\n{filename}") - if not quiet: print(f"Added '{filename}' to {gitignore_path}") + if not quiet: + print(f"Added '{filename}' to {gitignore_path}") else: # Create a new .gitignore file and add the filename with open(gitignore_path, "w", encoding="utf-8") as gitignore_file: gitignore_file.write(f"{filename}\n") - if not quiet: print(f"Created {gitignore_path} and added '{filename}'") + if not quiet: + print(f"Created {gitignore_path} and added '{filename}'") def calculate_required_space(input=None, directory=None): @@ -144,6 +146,7 @@ def read_key_file(key_file, debug): debug_log(f"Debug: Key file {key_file} read successfully.", debug) return key + def conditional_echo(message, quiet, **kwargs): """ Echo a message only if `quiet` is False. @@ -151,9 +154,10 @@ def conditional_echo(message, quiet, **kwargs): if not quiet: click.echo(message, **kwargs) + def conditional_secho(message, quiet, **kwargs): """ Styled echo a message only if `quiet` is False. """ if not quiet: - click.secho(message, **kwargs) \ No newline at end of file + click.secho(message, **kwargs)