Skip to content

Commit

Permalink
Elevate specific Borg warnings to errors or squash errors to warnings…
Browse files Browse the repository at this point in the history
… (#798).
  • Loading branch information
witten committed Jan 21, 2024
1 parent 34f3c2b commit abf2b3a
Show file tree
Hide file tree
Showing 47 changed files with 1,156 additions and 132 deletions.
1 change: 1 addition & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
1.8.7.dev0
* #736: Store included configuration files within each backup archive in support of the "config
bootstrap" action. Previously, only top-level configuration files were stored.
* #798: Elevate specific Borg warnings to errors or squash errors to warnings.
* #810: SECURITY: Prevent shell injection attacks within the PostgreSQL hook, the MongoDB hook, the
SQLite hook, the "borgmatic borg" action, and command hook variable/constant interpolation.
* #814: Fix a traceback when providing an invalid "--override" value for a list option.
Expand Down
3 changes: 2 additions & 1 deletion borgmatic/borg/borg.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ def run_arbitrary_borg(
return execute_command(
tuple(shlex.quote(part) for part in full_command),
output_file=DO_NOT_CAPTURE,
borg_local_path=local_path,
shell=True,
extra_environment=dict(
(environment.make_environment(config) or {}),
Expand All @@ -68,4 +67,6 @@ def run_arbitrary_borg(
'ARCHIVE': archive if archive else '',
},
),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
7 changes: 6 additions & 1 deletion borgmatic/borg/break_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ def break_lock(
)

borg_environment = environment.make_environment(config)
execute_command(full_command, borg_local_path=local_path, extra_environment=borg_environment)
execute_command(
full_command,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
14 changes: 12 additions & 2 deletions borgmatic/borg/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,15 +434,25 @@ def check_archives(
)

borg_environment = environment.make_environment(config)
borg_exit_codes = config.get('borg_exit_codes')

# The Borg repair option triggers an interactive prompt, which won't work when output is
# captured. And progress messes with the terminal directly.
if check_arguments.repair or check_arguments.progress:
execute_command(
full_command, output_file=DO_NOT_CAPTURE, extra_environment=borg_environment
full_command,
output_file=DO_NOT_CAPTURE,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
else:
execute_command(full_command, extra_environment=borg_environment)
execute_command(
full_command,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)

for check in checks:
write_check_time(
Expand Down
3 changes: 2 additions & 1 deletion borgmatic/borg/compact.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def compact_segments(
execute_command(
full_command,
output_log_level=logging.INFO,
borg_local_path=local_path,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
12 changes: 9 additions & 3 deletions borgmatic/borg/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ def any_parent_directories(path, candidate_parents):


def collect_special_file_paths(
create_command, local_path, working_directory, borg_environment, skip_directories
create_command, config, local_path, working_directory, borg_environment, skip_directories
):
'''
Given a Borg create command as a tuple, a local Borg path, a working directory, a dict of
Expand All @@ -290,6 +290,7 @@ def collect_special_file_paths(
working_directory=working_directory,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)

paths = tuple(
Expand Down Expand Up @@ -469,6 +470,7 @@ def create_archive(
logger.debug(f'{repository_path}: Collecting special file paths')
special_file_paths = collect_special_file_paths(
create_flags + create_positional_arguments,
config,
local_path,
working_directory,
borg_environment,
Expand All @@ -494,30 +496,34 @@ def create_archive(
+ (('--progress',) if progress else ())
+ (('--json',) if json else ())
)
borg_exit_codes = config.get('borg_exit_codes')

if stream_processes:
return execute_command_with_processes(
create_flags + create_positional_arguments,
stream_processes,
output_log_level,
output_file,
borg_local_path=local_path,
working_directory=working_directory,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
elif output_log_level is None:
return execute_command_and_capture_output(
create_flags + create_positional_arguments,
working_directory=working_directory,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
else:
execute_command(
create_flags + create_positional_arguments,
output_log_level,
output_file,
borg_local_path=local_path,
working_directory=working_directory,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
4 changes: 4 additions & 0 deletions borgmatic/borg/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ def make_environment(config):
if value is not None:
environment[environment_variable_name] = 'YES' if value else 'NO'

# On Borg 1.4.0a1+, take advantage of more specific exit codes. No effect on
# older versions of Borg.
environment['BORG_EXIT_CODES'] = 'modern'

return environment
3 changes: 2 additions & 1 deletion borgmatic/borg/export_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def export_key(
full_command,
output_file=output_file,
output_log_level=logging.ANSWER,
borg_local_path=local_path,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
3 changes: 2 additions & 1 deletion borgmatic/borg/export_tar.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def export_tar_archive(
full_command,
output_file=DO_NOT_CAPTURE if destination_path == '-' else None,
output_log_level=output_log_level,
borg_local_path=local_path,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
17 changes: 15 additions & 2 deletions borgmatic/borg/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ def extract_last_archive_dry_run(
)

execute_command(
full_extract_command, working_directory=None, extra_environment=borg_environment
full_extract_command,
working_directory=None,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)


Expand Down Expand Up @@ -127,6 +131,7 @@ def extract_archive(
)

borg_environment = environment.make_environment(config)
borg_exit_codes = config.get('borg_exit_codes')

# The progress output isn't compatible with captured and logged output, as progress messes with
# the terminal directly.
Expand All @@ -136,6 +141,8 @@ def extract_archive(
output_file=DO_NOT_CAPTURE,
working_directory=destination_path,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
return None

Expand All @@ -146,10 +153,16 @@ def extract_archive(
working_directory=destination_path,
run_to_completion=False,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)

# Don't give Borg local path so as to error on warnings, as "borg extract" only gives a warning
# if the restore paths don't exist in the archive.
execute_command(
full_command, working_directory=destination_path, extra_environment=borg_environment
full_command,
working_directory=destination_path,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
5 changes: 4 additions & 1 deletion borgmatic/borg/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,13 @@ def display_archives_info(
local_path,
remote_path,
)
borg_exit_codes = config.get('borg_exit_codes')

json_info = execute_command_and_capture_output(
json_command,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)

if info_arguments.json:
Expand All @@ -110,6 +112,7 @@ def display_archives_info(
execute_command(
main_command,
output_log_level=logging.ANSWER,
borg_local_path=local_path,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
6 changes: 5 additions & 1 deletion borgmatic/borg/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ def capture_archive_listing(
),
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
.strip('\n')
.split('\n')
Expand Down Expand Up @@ -189,6 +190,7 @@ def list_archive(
)

borg_environment = environment.make_environment(config)
borg_exit_codes = config.get('borg_exit_codes')

# If there are any paths to find (and there's not a single archive already selected), start by
# getting a list of archives to search.
Expand Down Expand Up @@ -219,6 +221,7 @@ def list_archive(
),
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
.strip('\n')
.split('\n')
Expand Down Expand Up @@ -251,6 +254,7 @@ def list_archive(
execute_command(
main_command,
output_log_level=logging.ANSWER,
borg_local_path=local_path,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
10 changes: 8 additions & 2 deletions borgmatic/borg/mount.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,15 @@ def mount_archive(
execute_command(
full_command,
output_file=DO_NOT_CAPTURE,
borg_local_path=local_path,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
return

execute_command(full_command, borg_local_path=local_path, extra_environment=borg_environment)
execute_command(
full_command,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
3 changes: 2 additions & 1 deletion borgmatic/borg/prune.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def prune_archives(
execute_command(
full_command,
output_log_level=output_log_level,
borg_local_path=local_path,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
3 changes: 2 additions & 1 deletion borgmatic/borg/rcreate.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def create_repository(
execute_command(
rcreate_command,
output_file=DO_NOT_CAPTURE,
borg_local_path=local_path,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
5 changes: 4 additions & 1 deletion borgmatic/borg/rinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,20 @@ def display_repository_info(
)

extra_environment = environment.make_environment(config)
borg_exit_codes = config.get('borg_exit_codes')

if rinfo_arguments.json:
return execute_command_and_capture_output(
full_command,
extra_environment=extra_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
else:
execute_command(
full_command,
output_log_level=logging.ANSWER,
borg_local_path=local_path,
extra_environment=extra_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
10 changes: 8 additions & 2 deletions borgmatic/borg/rlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def resolve_archive_name(
full_command,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)
try:
latest_archive = output.strip().splitlines()[-1]
Expand Down Expand Up @@ -147,9 +148,13 @@ def list_repository(
local_path,
remote_path,
)
borg_exit_codes = config.get('borg_exit_codes')

json_listing = execute_command_and_capture_output(
json_command, extra_environment=borg_environment, borg_local_path=local_path
json_command,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)

if rlist_arguments.json:
Expand All @@ -160,6 +165,7 @@ def list_repository(
execute_command(
main_command,
output_log_level=logging.ANSWER,
borg_local_path=local_path,
extra_environment=borg_environment,
borg_local_path=local_path,
borg_exit_codes=borg_exit_codes,
)
1 change: 1 addition & 0 deletions borgmatic/borg/transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,6 @@ def transfer_archives(
output_log_level=logging.ANSWER,
output_file=DO_NOT_CAPTURE if transfer_arguments.progress else None,
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
extra_environment=environment.make_environment(config),
)
6 changes: 4 additions & 2 deletions borgmatic/borg/umount.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
logger = logging.getLogger(__name__)


def unmount_archive(mount_point, local_path='borg'):
def unmount_archive(config, mount_point, local_path='borg'):
'''
Given a mounted filesystem mount point, and an optional local Borg paths, umount the filesystem
from the mount point.
Expand All @@ -17,4 +17,6 @@ def unmount_archive(mount_point, local_path='borg'):
+ (mount_point,)
)

execute_command(full_command)
execute_command(
full_command, borg_local_path=local_path, borg_exit_codes=config.get('borg_exit_codes')
)
1 change: 1 addition & 0 deletions borgmatic/borg/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def local_borg_version(config, local_path='borg'):
full_command,
extra_environment=environment.make_environment(config),
borg_local_path=local_path,
borg_exit_codes=config.get('borg_exit_codes'),
)

try:
Expand Down
1 change: 1 addition & 0 deletions borgmatic/commands/borgmatic.py
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ def collect_configuration_run_summary_logs(configs, config_paths, arguments):
logger.info(f"Unmounting mount point {arguments['umount'].mount_point}")
try:
borg_umount.unmount_archive(
config,
mount_point=arguments['umount'].mount_point,
local_path=get_local_path(configs),
)
Expand Down
Loading

0 comments on commit abf2b3a

Please sign in to comment.