Explorar o código

Apply the "umask" option to all relevant actions, not just some of them (#441).

Dan Helfman hai 7 meses
pai
achega
13884bd448

+ 1 - 0
NEWS

@@ -1,4 +1,5 @@
 1.9.2.dev0
 1.9.2.dev0
+ * #441: Apply the "umask" option to all relevant actions, not just some of them.
  * #722: Remove the restriction that the "extract" and "mount" actions must match a single
  * #722: Remove the restriction that the "extract" and "mount" actions must match a single
    repository. Now they work more like other actions, where each repository is applied in turn.
    repository. Now they work more like other actions, where each repository is applied in turn.
  * #932: Fix the missing build backend setting in pyproject.toml to allow Fedora builds.
  * #932: Fix the missing build backend setting in pyproject.toml to allow Fedora builds.

+ 2 - 0
borgmatic/borg/check.py

@@ -150,6 +150,7 @@ def check_archives(
         )
         )
 
 
     max_duration = check_arguments.max_duration or repository_check_config.get('max_duration')
     max_duration = check_arguments.max_duration or repository_check_config.get('max_duration')
+    umask = config.get('umask')
 
 
     borg_environment = environment.make_environment(config)
     borg_environment = environment.make_environment(config)
     borg_exit_codes = config.get('borg_exit_codes')
     borg_exit_codes = config.get('borg_exit_codes')
@@ -160,6 +161,7 @@ def check_archives(
         + (('--max-duration', str(max_duration)) if max_duration else ())
         + (('--max-duration', str(max_duration)) if max_duration else ())
         + make_check_name_flags(checks, archive_filter_flags)
         + make_check_name_flags(checks, archive_filter_flags)
         + (('--remote-path', remote_path) if remote_path else ())
         + (('--remote-path', remote_path) if remote_path else ())
+        + (('--umask', str(umask)) if umask else ())
         + (('--log-json',) if global_arguments.log_json else ())
         + (('--log-json',) if global_arguments.log_json else ())
         + (('--lock-wait', str(lock_wait)) if lock_wait else ())
         + (('--lock-wait', str(lock_wait)) if lock_wait else ())
         + verbosity_flags
         + verbosity_flags

+ 1 - 0
borgmatic/borg/delete.py

@@ -31,6 +31,7 @@ def make_delete_command(
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + borgmatic.borg.flags.make_flags('dry-run', global_arguments.dry_run)
         + borgmatic.borg.flags.make_flags('dry-run', global_arguments.dry_run)
         + borgmatic.borg.flags.make_flags('remote-path', remote_path)
         + borgmatic.borg.flags.make_flags('remote-path', remote_path)
+        + borgmatic.borg.flags.make_flags('umask', config.get('umask'))
         + borgmatic.borg.flags.make_flags('log-json', global_arguments.log_json)
         + borgmatic.borg.flags.make_flags('log-json', global_arguments.log_json)
         + borgmatic.borg.flags.make_flags('lock-wait', config.get('lock_wait'))
         + borgmatic.borg.flags.make_flags('lock-wait', config.get('lock_wait'))
         + borgmatic.borg.flags.make_flags('list', delete_arguments.list_archives)
         + borgmatic.borg.flags.make_flags('list', delete_arguments.list_archives)

+ 1 - 0
borgmatic/borg/info.py

@@ -36,6 +36,7 @@ def make_info_command(
             else ()
             else ()
         )
         )
         + flags.make_flags('remote-path', remote_path)
         + flags.make_flags('remote-path', remote_path)
+        + flags.make_flags('umask', config.get('umask'))
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('lock-wait', config.get('lock_wait'))
         + flags.make_flags('lock-wait', config.get('lock_wait'))
         + (
         + (

+ 2 - 3
borgmatic/borg/list.py

@@ -34,8 +34,6 @@ def make_list_command(
     and local and remote Borg paths, return a command as a tuple to list archives or paths within an
     and local and remote Borg paths, return a command as a tuple to list archives or paths within an
     archive.
     archive.
     '''
     '''
-    lock_wait = config.get('lock_wait', None)
-
     return (
     return (
         (local_path, 'list')
         (local_path, 'list')
         + (
         + (
@@ -49,8 +47,9 @@ def make_list_command(
             else ()
             else ()
         )
         )
         + flags.make_flags('remote-path', remote_path)
         + flags.make_flags('remote-path', remote_path)
+        + flags.make_flags('umask', config.get('umask'))
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('log-json', global_arguments.log_json)
-        + flags.make_flags('lock-wait', lock_wait)
+        + flags.make_flags('lock-wait', config.get('lock_wait'))
         + flags.make_flags_from_arguments(list_arguments, excludes=MAKE_FLAGS_EXCLUDES)
         + flags.make_flags_from_arguments(list_arguments, excludes=MAKE_FLAGS_EXCLUDES)
         + (
         + (
             flags.make_repository_archive_flags(
             flags.make_repository_archive_flags(

+ 2 - 0
borgmatic/borg/repo_create.py

@@ -64,6 +64,7 @@ def create_repository(
             raise
             raise
 
 
     lock_wait = config.get('lock_wait')
     lock_wait = config.get('lock_wait')
+    umask = config.get('umask')
     extra_borg_options = config.get('extra_borg_options', {}).get('repo-create', '')
     extra_borg_options = config.get('extra_borg_options', {}).get('repo-create', '')
 
 
     repo_create_command = (
     repo_create_command = (
@@ -84,6 +85,7 @@ def create_repository(
         + (('--log-json',) if global_arguments.log_json else ())
         + (('--log-json',) if global_arguments.log_json else ())
         + (('--lock-wait', str(lock_wait)) if lock_wait else ())
         + (('--lock-wait', str(lock_wait)) if lock_wait else ())
         + (('--remote-path', remote_path) if remote_path else ())
         + (('--remote-path', remote_path) if remote_path else ())
+        + (('--umask', str(umask)) if umask else ())
         + (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
         + (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
         + flags.make_repository_flags(repository_path, local_borg_version)
         + flags.make_repository_flags(repository_path, local_borg_version)
     )
     )

+ 1 - 0
borgmatic/borg/repo_delete.py

@@ -36,6 +36,7 @@ def make_repo_delete_command(
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + borgmatic.borg.flags.make_flags('dry-run', global_arguments.dry_run)
         + borgmatic.borg.flags.make_flags('dry-run', global_arguments.dry_run)
         + borgmatic.borg.flags.make_flags('remote-path', remote_path)
         + borgmatic.borg.flags.make_flags('remote-path', remote_path)
+        + borgmatic.borg.flags.make_flags('umask', config.get('umask'))
         + borgmatic.borg.flags.make_flags('log-json', global_arguments.log_json)
         + borgmatic.borg.flags.make_flags('log-json', global_arguments.log_json)
         + borgmatic.borg.flags.make_flags('lock-wait', config.get('lock_wait'))
         + borgmatic.borg.flags.make_flags('lock-wait', config.get('lock_wait'))
         + borgmatic.borg.flags.make_flags('list', repo_delete_arguments.list_archives)
         + borgmatic.borg.flags.make_flags('list', repo_delete_arguments.list_archives)

+ 1 - 0
borgmatic/borg/repo_info.py

@@ -43,6 +43,7 @@ def display_repository_info(
             else ()
             else ()
         )
         )
         + flags.make_flags('remote-path', remote_path)
         + flags.make_flags('remote-path', remote_path)
+        + flags.make_flags('umask', config.get('umask'))
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('lock-wait', lock_wait)
         + flags.make_flags('lock-wait', lock_wait)
         + (('--json',) if repo_info_arguments.json else ())
         + (('--json',) if repo_info_arguments.json else ())

+ 2 - 0
borgmatic/borg/repo_list.py

@@ -39,6 +39,7 @@ def resolve_archive_name(
             ),
             ),
         )
         )
         + flags.make_flags('remote-path', remote_path)
         + flags.make_flags('remote-path', remote_path)
+        + flags.make_flags('umask', config.get('umask'))
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('lock-wait', config.get('lock_wait'))
         + flags.make_flags('lock-wait', config.get('lock_wait'))
         + flags.make_flags('last', 1)
         + flags.make_flags('last', 1)
@@ -100,6 +101,7 @@ def make_repo_list_command(
             else ()
             else ()
         )
         )
         + flags.make_flags('remote-path', remote_path)
         + flags.make_flags('remote-path', remote_path)
+        + flags.make_flags('umask', config.get('umask'))
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('lock-wait', config.get('lock_wait'))
         + flags.make_flags('lock-wait', config.get('lock_wait'))
         + (
         + (

+ 1 - 0
borgmatic/borg/transfer.py

@@ -30,6 +30,7 @@ def transfer_archives(
         + (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
         + (('--info',) if logger.getEffectiveLevel() == logging.INFO else ())
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + flags.make_flags('remote-path', remote_path)
         + flags.make_flags('remote-path', remote_path)
+        + flags.make_flags('umask', config.get('umask'))
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('lock-wait', config.get('lock_wait', None))
         + flags.make_flags('lock-wait', config.get('lock_wait', None))
         + (
         + (

+ 25 - 0
tests/unit/borg/test_check.py

@@ -703,6 +703,31 @@ def test_check_archives_with_remote_path_passes_through_to_borg():
     )
     )
 
 
 
 
+def test_check_archives_with_umask_passes_through_to_borg():
+    checks = {'repository'}
+    config = {'umask': '077'}
+    flexmock(module).should_receive('make_check_name_flags').with_args(checks, ()).and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
+    insert_execute_command_mock(('borg', 'check', '--umask', '077', 'repo'))
+
+    module.check_archives(
+        repository_path='repo',
+        config=config,
+        local_borg_version='1.2.3',
+        check_arguments=flexmock(
+            progress=None,
+            repair=None,
+            only_checks=None,
+            force=None,
+            match_archives=None,
+            max_duration=None,
+        ),
+        global_arguments=flexmock(log_json=False),
+        checks=checks,
+        archive_filter_flags=(),
+    )
+
+
 def test_check_archives_with_log_json_passes_through_to_borg():
 def test_check_archives_with_log_json_passes_through_to_borg():
     checks = {'repository'}
     checks = {'repository'}
     config = {}
     config = {}

+ 23 - 0
tests/unit/borg/test_delete.py

@@ -100,6 +100,29 @@ def test_make_delete_command_includes_remote_path():
     assert command == ('borg', 'delete', '--remote-path', 'borg1', 'repo')
     assert command == ('borg', 'delete', '--remote-path', 'borg1', 'repo')
 
 
 
 
+def test_make_delete_command_includes_umask():
+    flexmock(module.borgmatic.borg.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.borgmatic.borg.flags).should_receive('make_match_archives_flags').and_return(())
+    flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
+        ('repo',)
+    )
+
+    command = module.make_delete_command(
+        repository={'path': 'repo'},
+        config={'umask': '077'},
+        local_borg_version='1.2.3',
+        delete_arguments=flexmock(list_archives=False, force=0, match_archives=None, archive=None),
+        global_arguments=flexmock(dry_run=False, log_json=False),
+        local_path='borg',
+        remote_path=None,
+    )
+
+    assert command == ('borg', 'delete', '--umask', '077', 'repo')
+
+
 def test_make_delete_command_includes_log_json():
 def test_make_delete_command_includes_log_json():
     flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
     flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
     flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args(
     flexmock(module.borgmatic.borg.flags).should_receive('make_flags').with_args(

+ 23 - 0
tests/unit/borg/test_info.py

@@ -203,6 +203,29 @@ def test_make_info_command_with_remote_path_passes_through_to_command():
     assert command == ('borg', 'info', '--remote-path', 'borg1', '--repo', 'repo')
     assert command == ('borg', 'info', '--remote-path', 'borg1', '--repo', 'repo')
 
 
 
 
+def test_make_info_command_with_umask_passes_through_to_command():
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
+        None, None, '2.3.4'
+    ).and_return(())
+    flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
+
+    command = module.make_info_command(
+        repository_path='repo',
+        config={'umask': '077'},
+        local_borg_version='2.3.4',
+        global_arguments=flexmock(log_json=False),
+        info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None),
+        local_path='borg',
+        remote_path=None,
+    )
+
+    assert command == ('borg', 'info', '--umask', '077', '--repo', 'repo')
+
+
 def test_make_info_command_with_log_json_passes_through_to_command():
 def test_make_info_command_with_log_json_passes_through_to_command():
     flexmock(module.flags).should_receive('make_flags').and_return(())
     flexmock(module.flags).should_receive('make_flags').and_return(())
     flexmock(module.flags).should_receive('make_flags').with_args('log-json', True).and_return(
     flexmock(module.flags).should_receive('make_flags').with_args('log-json', True).and_return(

+ 22 - 2
tests/unit/borg/test_list.py

@@ -94,7 +94,9 @@ def test_make_list_command_includes_json():
 
 
 
 
 def test_make_list_command_includes_log_json():
 def test_make_list_command_includes_log_json():
-    flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(('--log-json',))
+    flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
+        ('--log-json',)
+    )
     flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
     flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
 
 
@@ -110,7 +112,7 @@ def test_make_list_command_includes_log_json():
 
 
 
 
 def test_make_list_command_includes_lock_wait():
 def test_make_list_command_includes_lock_wait():
-    flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(
+    flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
         ('--lock-wait', '5')
         ('--lock-wait', '5')
     )
     )
     flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
     flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
@@ -203,6 +205,24 @@ def test_make_list_command_includes_remote_path():
     assert command == ('borg', 'list', '--remote-path', 'borg2', 'repo')
     assert command == ('borg', 'list', '--remote-path', 'borg2', 'repo')
 
 
 
 
+def test_make_list_command_includes_umask():
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
+
+    command = module.make_list_command(
+        repository_path='repo',
+        config={'umask': '077'},
+        local_borg_version='1.2.3',
+        list_arguments=flexmock(archive=None, paths=None, json=False),
+        global_arguments=flexmock(log_json=False),
+    )
+
+    assert command == ('borg', 'list', '--umask', '077', 'repo')
+
+
 def test_make_list_command_includes_short():
 def test_make_list_command_includes_short():
     flexmock(module.flags).should_receive('make_flags').and_return(())
     flexmock(module.flags).should_receive('make_flags').and_return(())
     flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--short',))
     flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--short',))

+ 21 - 0
tests/unit/borg/test_repo_create.py

@@ -438,6 +438,27 @@ def test_create_repository_with_remote_path_calls_borg_with_remote_path_flag():
     )
     )
 
 
 
 
+def test_create_repository_with_umask_calls_borg_with_umask_flag():
+    insert_repo_info_command_not_found_mock()
+    insert_repo_create_command_mock(REPO_CREATE_COMMAND + ('--umask', '077', '--repo', 'repo'))
+    flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(
+        (
+            '--repo',
+            'repo',
+        )
+    )
+
+    module.create_repository(
+        dry_run=False,
+        repository_path='repo',
+        config={'umask': '077'},
+        local_borg_version='2.3.4',
+        global_arguments=flexmock(log_json=False),
+        encryption_mode='repokey',
+    )
+
+
 def test_create_repository_with_extra_borg_options_calls_borg_with_extra_options():
 def test_create_repository_with_extra_borg_options_calls_borg_with_extra_options():
     insert_repo_info_command_not_found_mock()
     insert_repo_info_command_not_found_mock()
     insert_repo_create_command_mock(
     insert_repo_create_command_mock(

+ 23 - 0
tests/unit/borg/test_repo_delete.py

@@ -141,6 +141,29 @@ def test_make_repo_delete_command_includes_remote_path():
     assert command == ('borg', 'repo-delete', '--remote-path', 'borg1', 'repo')
     assert command == ('borg', 'repo-delete', '--remote-path', 'borg1', 'repo')
 
 
 
 
+def test_make_repo_delete_command_includes_umask():
+    flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
+    flexmock(module.borgmatic.borg.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.borgmatic.borg.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.borgmatic.borg.flags).should_receive('make_repository_flags').and_return(
+        ('repo',)
+    )
+
+    command = module.make_repo_delete_command(
+        repository={'path': 'repo'},
+        config={'umask': '077'},
+        local_borg_version='1.2.3',
+        repo_delete_arguments=flexmock(list_archives=False, force=0),
+        global_arguments=flexmock(dry_run=False, log_json=False),
+        local_path='borg',
+        remote_path=None,
+    )
+
+    assert command == ('borg', 'repo-delete', '--umask', '077', 'repo')
+
+
 def test_make_repo_delete_command_includes_log_json():
 def test_make_repo_delete_command_includes_log_json():
     flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
     flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
     flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
     flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())

+ 84 - 0
tests/unit/borg/test_repo_info.py

@@ -11,6 +11,9 @@ def test_display_repository_info_calls_borg_with_flags():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -49,6 +52,9 @@ def test_display_repository_info_without_borg_features_calls_borg_with_info_sub_
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(False)
     flexmock(module.feature).should_receive('available').and_return(False)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
     flexmock(module.environment).should_receive('make_environment')
     flexmock(module.environment).should_receive('make_environment')
     flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
     flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
@@ -82,6 +88,9 @@ def test_display_repository_info_with_log_info_calls_borg_with_info_flag():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -120,6 +129,9 @@ def test_display_repository_info_with_log_info_and_json_suppresses_most_borg_out
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -153,6 +165,9 @@ def test_display_repository_info_with_log_debug_calls_borg_with_debug_flag():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -192,6 +207,9 @@ def test_display_repository_info_with_log_debug_and_json_suppresses_most_borg_ou
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -225,6 +243,9 @@ def test_display_repository_info_with_json_calls_borg_with_json_flag():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -257,6 +278,9 @@ def test_display_repository_info_with_local_path_calls_borg_via_local_path():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -296,6 +320,9 @@ def test_display_repository_info_with_exit_codes_calls_borg_using_them():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -335,6 +362,9 @@ def test_display_repository_info_with_remote_path_calls_borg_with_remote_path_fl
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -370,10 +400,58 @@ def test_display_repository_info_with_remote_path_calls_borg_with_remote_path_fl
     )
     )
 
 
 
 
+def test_display_repository_info_with_umask_calls_borg_with_umask_flags():
+    flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
+    flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
+    flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(
+        (
+            '--repo',
+            'repo',
+        )
+    )
+    flexmock(module.environment).should_receive('make_environment')
+    flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
+    flexmock(module).should_receive('execute_command_and_capture_output').with_args(
+        ('borg', 'repo-info', '--umask', '077', '--json', '--repo', 'repo'),
+        extra_environment=None,
+        working_directory=None,
+        borg_local_path='borg',
+        borg_exit_codes=None,
+    ).and_return('[]')
+    flexmock(module.flags).should_receive('warn_for_aggressive_archive_flags')
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'repo-info', '--umask', '077', '--repo', 'repo'),
+        output_log_level=module.borgmatic.logger.ANSWER,
+        extra_environment=None,
+        working_directory=None,
+        borg_local_path='borg',
+        borg_exit_codes=None,
+    )
+
+    module.display_repository_info(
+        repository_path='repo',
+        config={'umask': '077'},
+        local_borg_version='2.3.4',
+        repo_info_arguments=flexmock(json=False),
+        global_arguments=flexmock(log_json=False),
+        remote_path=None,
+    )
+
+
 def test_display_repository_info_with_log_json_calls_borg_with_log_json_flags():
 def test_display_repository_info_with_log_json_calls_borg_with_log_json_flags():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.flags).should_receive('make_flags').with_args('log-json', True).and_return(
+        ('--log-json',)
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -413,6 +491,9 @@ def test_display_repository_info_with_lock_wait_calls_borg_with_lock_wait_flags(
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     config = {'lock_wait': 5}
     config = {'lock_wait': 5}
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', str(value)) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',
@@ -451,6 +532,9 @@ def test_display_repository_info_calls_borg_with_working_directory():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
         (
             '--repo',
             '--repo',

+ 50 - 3
tests/unit/borg/test_repo_list.py

@@ -180,6 +180,30 @@ def test_resolve_archive_name_with_remote_path_calls_borg_with_remote_path_flags
     )
     )
 
 
 
 
+def test_resolve_archive_name_with_umask_calls_borg_with_umask_flags():
+    expected_archive = 'archive-name'
+    flexmock(module.environment).should_receive('make_environment')
+    flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
+    flexmock(module).should_receive('execute_command_and_capture_output').with_args(
+        ('borg', 'list', '--umask', '077') + BORG_LIST_LATEST_ARGUMENTS,
+        extra_environment=None,
+        working_directory=None,
+        borg_local_path='borg',
+        borg_exit_codes=None,
+    ).and_return(expected_archive + '\n')
+
+    assert (
+        module.resolve_archive_name(
+            'repo',
+            'latest',
+            config={'umask': '077'},
+            local_borg_version='1.2.3',
+            global_arguments=flexmock(log_json=False),
+        )
+        == expected_archive
+    )
+
+
 def test_resolve_archive_name_without_archives_raises():
 def test_resolve_archive_name_without_archives_raises():
     flexmock(module.environment).should_receive('make_environment')
     flexmock(module.environment).should_receive('make_environment')
     flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
     flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
@@ -455,9 +479,9 @@ def test_make_repo_list_command_includes_local_path():
 
 
 
 
 def test_make_repo_list_command_includes_remote_path():
 def test_make_repo_list_command_includes_remote_path():
-    flexmock(module.flags).should_receive('make_flags').and_return(
-        ('--remote-path', 'borg2')
-    ).and_return(()).and_return(())
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
     flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
     flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
         None, None, '1.2.3'
         None, None, '1.2.3'
     ).and_return(())
     ).and_return(())
@@ -478,6 +502,29 @@ def test_make_repo_list_command_includes_remote_path():
     assert command == ('borg', 'list', '--remote-path', 'borg2', 'repo')
     assert command == ('borg', 'list', '--remote-path', 'borg2', 'repo')
 
 
 
 
+def test_make_repo_list_command_includes_umask():
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
+        None, None, '1.2.3'
+    ).and_return(())
+    flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
+
+    command = module.make_repo_list_command(
+        repository_path='repo',
+        config={'umask': '077'},
+        local_borg_version='1.2.3',
+        repo_list_arguments=flexmock(
+            archive=None, paths=None, json=False, prefix=None, match_archives=None
+        ),
+        global_arguments=flexmock(log_json=False),
+    )
+
+    assert command == ('borg', 'list', '--umask', '077', 'repo')
+
+
 def test_make_repo_list_command_transforms_prefix_into_match_archives():
 def test_make_repo_list_command_transforms_prefix_into_match_archives():
     flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
     flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
         ('--match-archives', 'sh:foo*')
         ('--match-archives', 'sh:foo*')

+ 33 - 0
tests/unit/borg/test_transfer.py

@@ -334,6 +334,39 @@ def test_transfer_archives_with_remote_path_calls_borg_with_remote_path_flags():
     )
     )
 
 
 
 
+def test_transfer_archives_with_umask_calls_borg_with_umask_flags():
+    flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
+    flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
+    flexmock(module.flags).should_receive('make_flags').replace_with(
+        lambda name, value: (f'--{name}', value) if value else ()
+    )
+    flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
+    flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(())
+    flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo'))
+    flexmock(module.environment).should_receive('make_environment')
+    flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
+    flexmock(module).should_receive('execute_command').with_args(
+        ('borg', 'transfer', '--umask', '077', '--repo', 'repo'),
+        output_log_level=module.borgmatic.logger.ANSWER,
+        output_file=None,
+        extra_environment=None,
+        working_directory=None,
+        borg_local_path='borg',
+        borg_exit_codes=None,
+    )
+
+    module.transfer_archives(
+        dry_run=False,
+        repository_path='repo',
+        config={'umask': '077'},
+        local_borg_version='2.3.4',
+        transfer_arguments=flexmock(
+            archive=None, progress=None, match_archives=None, source_repository=None
+        ),
+        global_arguments=flexmock(log_json=False),
+    )
+
+
 def test_transfer_archives_with_log_json_calls_borg_with_log_json_flags():
 def test_transfer_archives_with_log_json_calls_borg_with_log_json_flags():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER