浏览代码

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

Dan Helfman 7 月之前
父节点
当前提交
13884bd448

+ 1 - 0
NEWS

@@ -1,4 +1,5 @@
 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
    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.

+ 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')
+    umask = config.get('umask')
 
     borg_environment = environment.make_environment(config)
     borg_exit_codes = config.get('borg_exit_codes')
@@ -160,6 +161,7 @@ def check_archives(
         + (('--max-duration', str(max_duration)) if max_duration else ())
         + make_check_name_flags(checks, archive_filter_flags)
         + (('--remote-path', remote_path) if remote_path else ())
+        + (('--umask', str(umask)) if umask else ())
         + (('--log-json',) if global_arguments.log_json else ())
         + (('--lock-wait', str(lock_wait)) if lock_wait else ())
         + 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 ())
         + 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('umask', config.get('umask'))
         + 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('list', delete_arguments.list_archives)

+ 1 - 0
borgmatic/borg/info.py

@@ -36,6 +36,7 @@ def make_info_command(
             else ()
         )
         + 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('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
     archive.
     '''
-    lock_wait = config.get('lock_wait', None)
-
     return (
         (local_path, 'list')
         + (
@@ -49,8 +47,9 @@ def make_list_command(
             else ()
         )
         + 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('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_repository_archive_flags(

+ 2 - 0
borgmatic/borg/repo_create.py

@@ -64,6 +64,7 @@ def create_repository(
             raise
 
     lock_wait = config.get('lock_wait')
+    umask = config.get('umask')
     extra_borg_options = config.get('extra_borg_options', {}).get('repo-create', '')
 
     repo_create_command = (
@@ -84,6 +85,7 @@ def create_repository(
         + (('--log-json',) if global_arguments.log_json else ())
         + (('--lock-wait', str(lock_wait)) if lock_wait 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 ())
         + 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 ())
         + 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('umask', config.get('umask'))
         + 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('list', repo_delete_arguments.list_archives)

+ 1 - 0
borgmatic/borg/repo_info.py

@@ -43,6 +43,7 @@ def display_repository_info(
             else ()
         )
         + 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('lock-wait', lock_wait)
         + (('--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('umask', config.get('umask'))
         + flags.make_flags('log-json', global_arguments.log_json)
         + flags.make_flags('lock-wait', config.get('lock_wait'))
         + flags.make_flags('last', 1)
@@ -100,6 +101,7 @@ def make_repo_list_command(
             else ()
         )
         + 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('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 ())
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + 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('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():
     checks = {'repository'}
     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')
 
 
+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():
     flexmock(module.borgmatic.borg.flags).should_receive('make_flags').and_return(())
     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')
 
 
+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():
     flexmock(module.flags).should_receive('make_flags').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():
-    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_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():
-    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')
     )
     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')
 
 
+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():
     flexmock(module.flags).should_receive('make_flags').and_return(())
     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():
     insert_repo_info_command_not_found_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')
 
 
+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():
     flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
     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.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',
@@ -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.logging).ANSWER = module.borgmatic.logger.ANSWER
     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.environment).should_receive('make_environment')
     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.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',
@@ -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.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',
@@ -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.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',
@@ -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.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',
@@ -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.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',
@@ -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.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',
@@ -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.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',
@@ -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.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',
@@ -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():
     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_flags').with_args('log-json', True).and_return(
+        ('--log-json',)
+    )
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
         (
             '--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
     config = {'lock_wait': 5}
     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(
         (
             '--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.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',

+ 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():
     flexmock(module.environment).should_receive('make_environment')
     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():
-    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(
         None, None, '1.2.3'
     ).and_return(())
@@ -478,6 +502,29 @@ def test_make_repo_list_command_includes_remote_path():
     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():
     flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(()).and_return(
         ('--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():
     flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
     flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER