diff --git a/NEWS b/NEWS index 611d525f8..0707a3c37 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ 1.5.24.dev0 * #431: Add "working_directory" option to support source directories with relative paths. + * #444: When loading a configuration file that is unreadable due to file permissions, warn instead + of erroring. This supports running borgmatic as a non-root user with configuration in ~/.config + even if there is an unreadable global configuration file in /etc. * #486: Fix handling of "patterns_from" and "exclude_from" options to error instead of warning when referencing unreadable files and "create" action is run. * #507: Fix Borg usage error in the "compact" action when running "borgmatic --dry-run". Now, skip diff --git a/borgmatic/commands/borgmatic.py b/borgmatic/commands/borgmatic.py index 43ead04dd..7d70ea95f 100644 --- a/borgmatic/commands/borgmatic.py +++ b/borgmatic/commands/borgmatic.py @@ -646,6 +646,20 @@ def load_configurations(config_filenames, overrides=None): configs[config_filename] = validate.parse_configuration( config_filename, validate.schema_filename(), overrides ) + except PermissionError: + logs.extend( + [ + logging.makeLogRecord( + dict( + levelno=logging.WARNING, + levelname='WARNING', + msg='{}: Insufficient permissions to read configuration file'.format( + config_filename + ), + ) + ), + ] + ) except (ValueError, OSError, validate.Validation_error) as error: logs.extend( [ diff --git a/tests/unit/commands/test_borgmatic.py b/tests/unit/commands/test_borgmatic.py index 474f51726..2e0e79a1e 100644 --- a/tests/unit/commands/test_borgmatic.py +++ b/tests/unit/commands/test_borgmatic.py @@ -395,6 +395,15 @@ def test_load_configurations_collects_parsed_configurations(): assert logs == [] +def test_load_configurations_logs_warning_for_permission_error(): + flexmock(module.validate).should_receive('parse_configuration').and_raise(PermissionError) + + configs, logs = tuple(module.load_configurations(('test.yaml',))) + + assert configs == {} + assert {log.levelno for log in logs} == {logging.WARNING} + + def test_load_configurations_logs_critical_for_parse_error(): flexmock(module.validate).should_receive('parse_configuration').and_raise(ValueError)