فهرست منبع

Fix a bug in which quoted "extra_borg_options" values containing spaces are passed to Borg incorrectly. Add a "--comment" flag to the "create" action for creating an archive with a comment (#1108).

Dan Helfman 2 هفته پیش
والد
کامیت
1b62be0949

+ 3 - 0
NEWS

@@ -8,6 +8,9 @@
  * #1099: Clarify documentation on command hooks order of execution.
  * #1099: Clarify documentation on command hooks order of execution.
  * #1100: Fix a bug in which "borg --version" failing isn't considered a "fail" state in a command
  * #1100: Fix a bug in which "borg --version" failing isn't considered a "fail" state in a command
    hook.
    hook.
+ * #1108: Fix a bug in which quoted "extra_borg_options" values containing spaces are passed to Borg
+   incorrectly.
+ * #1108: Add a "--comment" flag to the "create" action for creating an archive with a comment.
  * Use the Bandit security analysis tool when running tests.
  * Use the Bandit security analysis tool when running tests.
  * SECURITY: Add timeouts to all monitoring hooks to prevent hangs on network requests.
  * SECURITY: Add timeouts to all monitoring hooks to prevent hangs on network requests.
  * SECURITY: For the "spot" check, use a more secure source of randomness when selecting paths to
  * SECURITY: For the "spot" check, use a more secure source of randomness when selecting paths to

+ 1 - 0
borgmatic/actions/create.py

@@ -92,6 +92,7 @@ def run_create(
             local_path=local_path,
             local_path=local_path,
             remote_path=remote_path,
             remote_path=remote_path,
             json=create_arguments.json,
             json=create_arguments.json,
+            comment=create_arguments.comment,
             stream_processes=stream_processes,
             stream_processes=stream_processes,
         )
         )
 
 

+ 2 - 1
borgmatic/borg/check.py

@@ -1,6 +1,7 @@
 import argparse
 import argparse
 import json
 import json
 import logging
 import logging
+import shlex
 
 
 import borgmatic.config.paths
 import borgmatic.config.paths
 from borgmatic.borg import environment, feature, flags, repo_info
 from borgmatic.borg import environment, feature, flags, repo_info
@@ -171,7 +172,7 @@ def check_archives(
             + (('--lock-wait', str(lock_wait)) if lock_wait else ())
             + (('--lock-wait', str(lock_wait)) if lock_wait else ())
             + verbosity_flags
             + verbosity_flags
             + (('--progress',) if config.get('progress') else ())
             + (('--progress',) if config.get('progress') else ())
-            + (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
+            + (tuple(shlex.split(extra_borg_options)) if extra_borg_options else ())
             + flags.make_repository_flags(repository_path, local_borg_version)
             + flags.make_repository_flags(repository_path, local_borg_version)
         )
         )
 
 

+ 2 - 1
borgmatic/borg/compact.py

@@ -1,4 +1,5 @@
 import logging
 import logging
+import shlex
 
 
 import borgmatic.config.paths
 import borgmatic.config.paths
 from borgmatic.borg import environment, feature, flags
 from borgmatic.borg import environment, feature, flags
@@ -42,7 +43,7 @@ def compact_segments(
             if dry_run and feature.available(feature.Feature.DRY_RUN_COMPACT, local_borg_version)
             if dry_run and feature.available(feature.Feature.DRY_RUN_COMPACT, local_borg_version)
             else ()
             else ()
         )
         )
-        + (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
+        + (tuple(shlex.split(extra_borg_options)) if extra_borg_options else ())
         + flags.make_repository_flags(repository_path, local_borg_version)
         + flags.make_repository_flags(repository_path, local_borg_version)
     )
     )
 
 

+ 17 - 7
borgmatic/borg/create.py

@@ -1,6 +1,7 @@
 import logging
 import logging
 import os
 import os
 import pathlib
 import pathlib
+import shlex
 import stat
 import stat
 import textwrap
 import textwrap
 
 
@@ -125,14 +126,17 @@ def make_base_create_command(
     local_path='borg',
     local_path='borg',
     remote_path=None,
     remote_path=None,
     json=False,
     json=False,
+    comment=None,
     stream_processes=None,
     stream_processes=None,
 ):
 ):
     '''
     '''
     Given verbosity/dry-run flags, a local or remote repository path, a configuration dict, a
     Given verbosity/dry-run flags, a local or remote repository path, a configuration dict, a
-    sequence of patterns as borgmatic.borg.pattern.Pattern instances, the local Borg version,
-    global arguments as an argparse.Namespace instance, and a sequence of borgmatic source
-    directories, return a tuple of (base Borg create command flags, Borg create command positional
-    arguments, open pattern file handle).
+    sequence of patterns as borgmatic.borg.pattern.Pattern instances, the local Borg version, global
+    arguments as an argparse.Namespace instance, the borgmatic runtime directory, a string suffix to
+    add to the archive name, the local Borg path, the remote Borg path, whether to output JSON,
+    comment text to add to the created archive, and a sequence of processes streaming data to Borg,
+    return a tuple of (base Borg create command flags, Borg create command positional arguments,
+    open pattern file handle).
     '''
     '''
     if config.get('source_directories_must_exist', False):
     if config.get('source_directories_must_exist', False):
         borgmatic.borg.pattern.check_all_root_patterns_exist(patterns)
         borgmatic.borg.pattern.check_all_root_patterns_exist(patterns)
@@ -185,6 +189,7 @@ def make_base_create_command(
         + ('create',)
         + ('create',)
         + (('--patterns-from', patterns_file.name) if patterns_file else ())
         + (('--patterns-from', patterns_file.name) if patterns_file else ())
         + flags.make_exclude_flags(config)
         + flags.make_exclude_flags(config)
+        + (('--comment', comment) if comment else ())
         + (('--checkpoint-interval', str(checkpoint_interval)) if checkpoint_interval else ())
         + (('--checkpoint-interval', str(checkpoint_interval)) if checkpoint_interval else ())
         + (('--checkpoint-volume', str(checkpoint_volume)) if checkpoint_volume else ())
         + (('--checkpoint-volume', str(checkpoint_volume)) if checkpoint_volume else ())
         + (('--chunker-params', chunker_params) if chunker_params else ())
         + (('--chunker-params', chunker_params) if chunker_params else ())
@@ -209,7 +214,7 @@ def make_base_create_command(
             else ()
             else ()
         )
         )
         + (('--dry-run',) if dry_run else ())
         + (('--dry-run',) if dry_run else ())
-        + (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
+        + (tuple(shlex.split(extra_borg_options)) if extra_borg_options else ())
     )
     )
 
 
     create_positional_arguments = flags.make_repository_archive_flags(
     create_positional_arguments = flags.make_repository_archive_flags(
@@ -275,12 +280,16 @@ def create_archive(
     local_path='borg',
     local_path='borg',
     remote_path=None,
     remote_path=None,
     json=False,
     json=False,
+    comment=None,
     stream_processes=None,
     stream_processes=None,
 ):
 ):
     '''
     '''
     Given verbosity/dry-run flags, a local or remote repository path, a configuration dict, a
     Given verbosity/dry-run flags, a local or remote repository path, a configuration dict, a
-    sequence of loaded configuration paths, the local Borg version, and global arguments as an
-    argparse.Namespace instance, create a Borg archive and return Borg's JSON output (if any).
+    sequence of loaded configuration paths, the local Borg version, global arguments as an
+    argparse.Namespace instance, the borgmatic runtime directory, a string suffix to add to the
+    archive name, the local Borg path, the remote Borg path, whether to output JSON, and comment
+    text to add to the created archive, and a sequence of processes streaming data to Borg, create a
+    Borg archive and return Borg's JSON output (if any).
 
 
     If a sequence of stream processes is given (instances of subprocess.Popen), then execute the
     If a sequence of stream processes is given (instances of subprocess.Popen), then execute the
     create command while also triggering the given processes to produce output.
     create command while also triggering the given processes to produce output.
@@ -301,6 +310,7 @@ def create_archive(
         local_path,
         local_path,
         remote_path,
         remote_path,
         json,
         json,
+        comment,
         stream_processes,
         stream_processes,
     )
     )
 
 

+ 2 - 1
borgmatic/borg/prune.py

@@ -1,4 +1,5 @@
 import logging
 import logging
+import shlex
 
 
 import borgmatic.config.paths
 import borgmatic.config.paths
 import borgmatic.logger
 import borgmatic.logger
@@ -90,7 +91,7 @@ def prune_archives(
         + (('--list',) if config.get('list_details') else ())
         + (('--list',) if config.get('list_details') else ())
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ())
         + (('--dry-run',) if dry_run else ())
         + (('--dry-run',) if dry_run else ())
-        + (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
+        + (tuple(shlex.split(extra_borg_options)) if extra_borg_options else ())
         + flags.make_repository_flags(repository_path, local_borg_version)
         + flags.make_repository_flags(repository_path, local_borg_version)
     )
     )
 
 

+ 2 - 1
borgmatic/borg/repo_create.py

@@ -1,6 +1,7 @@
 import argparse
 import argparse
 import json
 import json
 import logging
 import logging
+import shlex
 import subprocess
 import subprocess
 
 
 import borgmatic.config.paths
 import borgmatic.config.paths
@@ -86,7 +87,7 @@ def create_repository(
         + (('--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 ())
         + (('--umask', str(umask)) if umask else ())
-        + (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
+        + (tuple(shlex.split(extra_borg_options)) if extra_borg_options else ())
         + flags.make_repository_flags(repository_path, local_borg_version)
         + flags.make_repository_flags(repository_path, local_borg_version)
     )
     )
 
 

+ 5 - 0
borgmatic/commands/arguments.py

@@ -872,6 +872,11 @@ def make_parsers(schema, unparsed_arguments):
     create_group.add_argument(
     create_group.add_argument(
         '--json', dest='json', default=False, action='store_true', help='Output results as JSON'
         '--json', dest='json', default=False, action='store_true', help='Output results as JSON'
     )
     )
+    create_group.add_argument(
+        '--comment',
+        metavar='COMMENT',
+        help='Add a comment text to the archive',
+    )
     create_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
     create_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
 
 
     check_parser = action_parsers.add_parser(
     check_parser = action_parsers.add_parser(

+ 8 - 0
tests/unit/actions/test_create.py

@@ -26,6 +26,7 @@ def test_run_create_executes_and_calls_hooks_for_configured_repository():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=False,
         json=False,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
@@ -67,6 +68,7 @@ def test_run_create_runs_with_selected_repository():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=False,
         json=False,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
@@ -99,6 +101,7 @@ def test_run_create_bails_if_repository_does_not_match():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=False,
         json=False,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
@@ -131,6 +134,7 @@ def test_run_create_with_both_list_and_json_errors():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=True,
         json=True,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
@@ -164,6 +168,7 @@ def test_run_create_with_both_list_and_progress_errors():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=False,
         json=False,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
@@ -210,6 +215,7 @@ def test_run_create_produces_json():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=True,
         json=True,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
     global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
@@ -268,6 +274,7 @@ def test_run_create_with_active_dumps_roundtrips_via_checkpoint_archive():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=False,
         json=False,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
 
 
@@ -352,6 +359,7 @@ def test_run_create_with_active_dumps_json_updates_archive_info():
         progress=flexmock(),
         progress=flexmock(),
         statistics=flexmock(),
         statistics=flexmock(),
         json=True,
         json=True,
+        comment=None,
         list_details=flexmock(),
         list_details=flexmock(),
     )
     )
 
 

+ 4 - 2
tests/unit/borg/test_check.py

@@ -911,12 +911,14 @@ def test_check_archives_with_retention_prefix():
 
 
 
 
 def test_check_archives_with_extra_borg_options_passes_through_to_borg():
 def test_check_archives_with_extra_borg_options_passes_through_to_borg():
-    config = {'extra_borg_options': {'check': '--extra --options'}}
+    config = {'extra_borg_options': {'check': '--extra --options "value with space"'}}
     flexmock(module).should_receive('make_check_name_flags').with_args(
     flexmock(module).should_receive('make_check_name_flags').with_args(
         {'repository'}, ()
         {'repository'}, ()
     ).and_return(())
     ).and_return(())
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
-    insert_execute_command_mock(('borg', 'check', '--extra', '--options', 'repo'))
+    insert_execute_command_mock(
+        ('borg', 'check', '--extra', '--options', 'value with space', 'repo')
+    )
 
 
     module.check_archives(
     module.check_archives(
         repository_path='repo',
         repository_path='repo',

+ 4 - 2
tests/unit/borg/test_compact.py

@@ -232,12 +232,14 @@ def test_compact_segments_with_lock_wait_calls_borg_with_lock_wait_flags():
 
 
 def test_compact_segments_with_extra_borg_options_calls_borg_with_extra_options():
 def test_compact_segments_with_extra_borg_options_calls_borg_with_extra_options():
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
     flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
-    insert_execute_command_mock(COMPACT_COMMAND + ('--extra', '--options', 'repo'), logging.INFO)
+    insert_execute_command_mock(
+        COMPACT_COMMAND + ('--extra', '--options', 'value with space', 'repo'), logging.INFO
+    )
 
 
     module.compact_segments(
     module.compact_segments(
         dry_run=False,
         dry_run=False,
         repository_path='repo',
         repository_path='repo',
-        config={'extra_borg_options': {'compact': '--extra --options'}},
+        config={'extra_borg_options': {'compact': '--extra --options "value with space"'}},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
         global_arguments=flexmock(),
         global_arguments=flexmock(),
     )
     )

+ 70 - 2
tests/unit/borg/test_create.py

@@ -392,6 +392,39 @@ def test_make_base_create_command_includes_dry_run_in_borg_command():
     assert not pattern_file
     assert not pattern_file
 
 
 
 
+def test_make_base_create_command_includes_comment_in_borg_command():
+    flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
+    flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
+    flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
+    flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
+        '{hostname}'
+    )
+    flexmock(module.feature).should_receive('available').and_return(True)
+    flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
+    flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
+        (f'repo::{DEFAULT_ARCHIVE_NAME}',)
+    )
+
+    (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
+        dry_run=False,
+        repository_path='repo',
+        config={
+            'source_directories': ['foo', 'bar'],
+            'repositories': ['repo'],
+            'exclude_patterns': ['exclude'],
+        },
+        patterns=[Pattern('foo'), Pattern('bar')],
+        local_borg_version='1.2.3',
+        global_arguments=flexmock(),
+        borgmatic_runtime_directory='/run/borgmatic',
+        comment='a comment',
+    )
+
+    assert create_flags == ('borg', 'create', '--comment', 'a comment')
+    assert create_positional_arguments == REPO_ARCHIVE
+    assert not pattern_file
+
+
 def test_make_base_create_command_includes_local_path_in_borg_command():
 def test_make_base_create_command_includes_local_path_in_borg_command():
     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)
     flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
     flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
@@ -833,7 +866,7 @@ def test_make_base_create_command_includes_extra_borg_options_in_borg_command():
         config={
         config={
             'source_directories': ['foo', 'bar'],
             'source_directories': ['foo', 'bar'],
             'repositories': ['repo'],
             'repositories': ['repo'],
-            'extra_borg_options': {'create': '--extra --options'},
+            'extra_borg_options': {'create': '--extra --options "value with space"'},
         },
         },
         patterns=[Pattern('foo'), Pattern('bar')],
         patterns=[Pattern('foo'), Pattern('bar')],
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
@@ -841,7 +874,7 @@ def test_make_base_create_command_includes_extra_borg_options_in_borg_command():
         borgmatic_runtime_directory='/run/borgmatic',
         borgmatic_runtime_directory='/run/borgmatic',
     )
     )
 
 
-    assert create_flags == ('borg', 'create', '--extra', '--options')
+    assert create_flags == ('borg', 'create', '--extra', '--options', 'value with space')
     assert create_positional_arguments == REPO_ARCHIVE
     assert create_positional_arguments == REPO_ARCHIVE
     assert not pattern_file
     assert not pattern_file
 
 
@@ -1442,6 +1475,41 @@ def test_create_archive_with_stats_and_json_calls_borg_without_stats_flag():
     assert json_output == '[]'
     assert json_output == '[]'
 
 
 
 
+def test_create_archive_with_comment_calls_borg_with_comment_flag():
+    flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
+    flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
+    flexmock(module).should_receive('make_base_create_command').and_return(
+        (('borg', 'create', '--comment', 'a comment'), REPO_ARCHIVE, flexmock())
+    )
+    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', 'create', '--comment', 'a comment') + REPO_ARCHIVE,
+        output_log_level=logging.INFO,
+        output_file=None,
+        borg_local_path='borg',
+        borg_exit_codes=None,
+        working_directory=None,
+        environment=None,
+    )
+
+    module.create_archive(
+        dry_run=False,
+        repository_path='repo',
+        config={
+            'source_directories': ['foo', 'bar'],
+            'repositories': ['repo'],
+            'exclude_patterns': None,
+        },
+        patterns=[Pattern('foo'), Pattern('bar')],
+        local_borg_version='1.2.3',
+        global_arguments=flexmock(),
+        borgmatic_runtime_directory='/borgmatic/run',
+        json=False,
+        comment='a comment',
+    )
+
+
 def test_create_archive_calls_borg_with_working_directory():
 def test_create_archive_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

+ 4 - 2
tests/unit/borg/test_prune.py

@@ -472,13 +472,15 @@ def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
     flexmock(module.feature).should_receive('available').with_args(
     flexmock(module.feature).should_receive('available').with_args(
         module.feature.Feature.NO_PRUNE_STATS, '1.2.3'
         module.feature.Feature.NO_PRUNE_STATS, '1.2.3'
     ).and_return(False)
     ).and_return(False)
-    insert_execute_command_mock(PRUNE_COMMAND + ('--extra', '--options', 'repo'), logging.INFO)
+    insert_execute_command_mock(
+        PRUNE_COMMAND + ('--extra', '--options', 'value with space', 'repo'), logging.INFO
+    )
 
 
     prune_arguments = flexmock(statistics=False, list_details=False)
     prune_arguments = flexmock(statistics=False, list_details=False)
     module.prune_archives(
     module.prune_archives(
         dry_run=False,
         dry_run=False,
         repository_path='repo',
         repository_path='repo',
-        config={'extra_borg_options': {'prune': '--extra --options'}},
+        config={'extra_borg_options': {'prune': '--extra --options "value with space"'}},
         local_borg_version='1.2.3',
         local_borg_version='1.2.3',
         global_arguments=flexmock(),
         global_arguments=flexmock(),
         prune_arguments=prune_arguments,
         prune_arguments=prune_arguments,

+ 2 - 2
tests/unit/borg/test_repo_create.py

@@ -484,7 +484,7 @@ def test_create_repository_with_umask_calls_borg_with_umask_flag():
 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(
-        REPO_CREATE_COMMAND + ('--extra', '--options', '--repo', 'repo')
+        REPO_CREATE_COMMAND + ('--extra', '--options', 'value with space', '--repo', 'repo')
     )
     )
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.feature).should_receive('available').and_return(True)
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
     flexmock(module.flags).should_receive('make_repository_flags').and_return(
@@ -497,7 +497,7 @@ def test_create_repository_with_extra_borg_options_calls_borg_with_extra_options
     module.create_repository(
     module.create_repository(
         dry_run=False,
         dry_run=False,
         repository_path='repo',
         repository_path='repo',
-        config={'extra_borg_options': {'repo-create': '--extra --options'}},
+        config={'extra_borg_options': {'repo-create': '--extra --options "value with space"'}},
         local_borg_version='2.3.4',
         local_borg_version='2.3.4',
         global_arguments=flexmock(),
         global_arguments=flexmock(),
         encryption_mode='repokey',
         encryption_mode='repokey',