Revamp systemd credential syntax to be more consistent with constants (#966).
All checks were successful
build / test (push) Successful in 8m19s
build / docs (push) Successful in 1m39s

This commit is contained in:
Dan Helfman 2025-02-10 22:01:23 -08:00
commit 50096296da
28 changed files with 295 additions and 312 deletions

4
NEWS
View file

@ -1,6 +1,6 @@
1.9.10
* #966: Add a "!credential" tag for loading systemd credentials into borgmatic configuration
files. See the documentation for more information:
* #966: Add a "{credential ...}" syntax for loading systemd credentials into borgmatic
configuration files. See the documentation for more information:
https://torsion.org/borgmatic/docs/how-to/provide-your-passwords/
* #987: Fix a "list" action error when the "encryption_passcommand" option is set.
* #987: When both "encryption_passcommand" and "encryption_passphrase" are configured, prefer

View file

@ -1,7 +1,7 @@
import os
import borgmatic.borg.passcommand
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
OPTION_TO_ENVIRONMENT_VARIABLE = {
'borg_base_directory': 'BORG_BASE_DIR',
@ -41,7 +41,7 @@ def make_environment(config):
value = config.get(option_name)
if option_name in CREDENTIAL_OPTIONS and value is not None:
value = borgmatic.hooks.credential.tag.resolve_credential(value)
value = borgmatic.hooks.credential.parse.resolve_credential(value)
if value is not None:
environment[environment_variable_name] = str(value)

View file

@ -104,21 +104,6 @@ def raise_omit_node_error(loader, node):
)
def reserialize_tag_node(loader, tag_node):
'''
Given a ruamel.yaml loader and a node for a tag and value, convert the node back into a string
of the form "!tagname value" and return it. The idea is that downstream code, rather than this
file's YAML loading logic, should be responsible for interpreting this particular tag—since the
downstream code actually understands the meaning behind the tag.
Raise ValueError if the tag node's value isn't a string.
'''
if isinstance(tag_node.value, str):
return f'{tag_node.tag} {tag_node.value}'
raise ValueError(f'The value given for the {tag_node.tag} tag is invalid; use a string instead')
class Include_constructor(ruamel.yaml.SafeConstructor):
'''
A YAML "constructor" (a ruamel.yaml concept) that supports a custom "!include" tag for including
@ -137,7 +122,6 @@ class Include_constructor(ruamel.yaml.SafeConstructor):
config_paths=config_paths,
),
)
self.add_constructor('!credential', reserialize_tag_node)
# These are catch-all error handlers for tags that don't get applied and removed by
# deep_merge_nodes() below.

View file

@ -250,7 +250,7 @@ properties:
repositories that were initialized with passphrase/repokey/keyfile
encryption. Quote the value if it contains punctuation, so it parses
correctly. And backslash any quote or backslash literals as well.
Defaults to not set. Supports the "!credential" tag.
Defaults to not set. Supports the "{credential ...}" syntax.
example: "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
checkpoint_interval:
type: integer
@ -989,13 +989,15 @@ properties:
Username with which to connect to the database. Defaults
to the username of the current user. You probably want
to specify the "postgres" superuser here when the
database name is "all". Supports the "!credential" tag.
database name is "all". Supports the "{credential ...}"
syntax.
example: dbuser
restore_username:
type: string
description: |
Username with which to restore the database. Defaults to
the "username" option. Supports the "!credential" tag.
the "username" option. Supports the "{credential ...}"
syntax.
example: dbuser
password:
type: string
@ -1003,14 +1005,15 @@ properties:
Password with which to connect to the database. Omitting
a password will only work if PostgreSQL is configured to
trust the configured username without a password or you
create a ~/.pgpass file. Supports the "!credential" tag.
create a ~/.pgpass file. Supports the "{credential ...}"
syntax.
example: trustsome1
restore_password:
type: string
description: |
Password with which to connect to the restore database.
Defaults to the "password" option. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: trustsome1
no_owner:
type: boolean
@ -1171,13 +1174,14 @@ properties:
description: |
Username with which to connect to the database. Defaults
to the username of the current user. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: dbuser
restore_username:
type: string
description: |
Username with which to restore the database. Defaults to
the "username" option. Supports the "!credential" tag.
the "username" option. Supports the "{credential ...}"
syntax.
example: dbuser
password:
type: string
@ -1185,14 +1189,14 @@ properties:
Password with which to connect to the database. Omitting
a password will only work if MariaDB is configured to
trust the configured username without a password.
Supports the "!credential" tag.
Supports the "{credential ...}" syntax.
example: trustsome1
restore_password:
type: string
description: |
Password with which to connect to the restore database.
Defaults to the "password" option. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: trustsome1
mariadb_dump_command:
type: string
@ -1300,13 +1304,14 @@ properties:
description: |
Username with which to connect to the database. Defaults
to the username of the current user. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: dbuser
restore_username:
type: string
description: |
Username with which to restore the database. Defaults to
the "username" option. Supports the "!credential" tag.
the "username" option. Supports the "{credential ...}"
syntax.
example: dbuser
password:
type: string
@ -1314,14 +1319,14 @@ properties:
Password with which to connect to the database. Omitting
a password will only work if MySQL is configured to
trust the configured username without a password.
Supports the "!credential" tag.
Supports the "{credential ...}" syntax.
example: trustsome1
restore_password:
type: string
description: |
Password with which to connect to the restore database.
Defaults to the "password" option. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: trustsome1
mysql_dump_command:
type: string
@ -1459,27 +1464,28 @@ properties:
description: |
Username with which to connect to the database. Skip it
if no authentication is needed. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: dbuser
restore_username:
type: string
description: |
Username with which to restore the database. Defaults to
the "username" option. Supports the "!credential" tag.
the "username" option. Supports the "{credential ...}"
syntax.
example: dbuser
password:
type: string
description: |
Password with which to connect to the database. Skip it
if no authentication is needed. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: trustsome1
restore_password:
type: string
description: |
Password with which to connect to the restore database.
Defaults to the "password" option. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: trustsome1
authentication_database:
type: string
@ -1539,19 +1545,19 @@ properties:
type: string
description: |
The username used for authentication. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: testuser
password:
type: string
description: |
The password used for authentication. Supports the
"!credential" tag.
"{credential ...}" syntax.
example: fakepassword
access_token:
type: string
description: |
An ntfy access token to authenticate with instead of
username/password. Supports the "!credential" tag.
username/password. Supports the "{credential ...}" syntax.
example: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2
start:
type: object
@ -1646,8 +1652,8 @@ properties:
token:
type: string
description: |
Your application's API token. Supports the "!credential"
tag.
Your application's API token. Supports the "{credential
...}" syntax.
example: 7ms6TXHpTokTou2P6x4SodDeentHRa
user:
type: string
@ -1655,7 +1661,7 @@ properties:
Your user/group key (or that of your target user), viewable
when logged into your dashboard: often referred to as
USER_KEY in Pushover documentation and code examples.
Supports the "!credential" tag.
Supports the "{credential ...}" syntax.
example: hwRwoWsXMBWwgrSecfa9EfPey55WSN
start:
type: object
@ -1929,19 +1935,19 @@ properties:
type: string
description: |
The username used for authentication. Not needed if using
an API key. Supports the "!credential" tag.
an API key. Supports the "{credential ...}" syntax.
example: testuser
password:
type: string
description: |
The password used for authentication. Not needed if using
an API key. Supports the "!credential" tag.
an API key. Supports the "{credential ...}" syntax.
example: fakepassword
api_key:
type: string
description: |
The API key used for authentication. Not needed if using
an username/password. Supports the "!credential" tag.
The API key used for authentication. Not needed if using an
username/password. Supports the "{credential ...}" syntax.
example: fakekey
start:
type: object
@ -2221,8 +2227,8 @@ properties:
integration_key:
type: string
description: |
PagerDuty integration key used to notify PagerDuty
when a backup errors. Supports the "!credential" tag.
PagerDuty integration key used to notify PagerDuty when a
backup errors. Supports the "{credential ...}" syntax.
example: a177cad45bd374409f78906a810a3074
description: |
Configuration for a monitoring integration with PagerDuty. Create an

View file

@ -0,0 +1,42 @@
import functools
import re
import borgmatic.hooks.dispatch
IS_A_HOOK = False
CREDENTIAL_PATTERN = re.compile(
r'\{credential +(?P<hook_name>[A-Za-z0-9_]+) +(?P<credential_name>[A-Za-z0-9_]+)\}'
)
GENERAL_CREDENTIAL_PATTERN = re.compile(r'\{credential( +[^}]*)?\}')
@functools.cache
def resolve_credential(value):
'''
Given a configuration value containing a string like "{credential hookname credentialname}", resolve it by
calling the relevant hook to get the actual credential value. If the given value does not
actually contain a credential tag, then return it unchanged.
Cache the value so repeated calls to this function don't need to load the credential repeatedly.
Raise ValueError if the config could not be parsed or the credential could not be loaded.
'''
if value is None:
return value
result = CREDENTIAL_PATTERN.sub(
lambda matcher: borgmatic.hooks.dispatch.call_hook(
'load_credential', {}, matcher.group('hook_name'), matcher.group('credential_name')
),
value,
)
# If we've tried to parse the credential, but the parsed result still looks kind of like a
# credential, it means it's invalid syntax.
if GENERAL_CREDENTIAL_PATTERN.match(result):
raise ValueError(f'Cannot load credential with invalid syntax "{value}"')
return result

View file

@ -1,27 +0,0 @@
import functools
import borgmatic.hooks.dispatch
IS_A_HOOK = False
@functools.cache
def resolve_credential(tag):
'''
Given a configuration tag string like "!credential hookname credentialname", resolve it by
calling the relevant hook to get the actual credential value. If the given tag is not actually a
credential tag, then return the value unchanged.
Cache the value so repeated calls to this function don't need to load the credential repeatedly.
Raise ValueError if the config could not be parsed or the credential could not be loaded.
'''
if tag and tag.startswith('!credential '):
try:
(tag_name, hook_name, credential_name) = tag.split(' ', 2)
except ValueError:
raise ValueError(f'Cannot load credential with invalid syntax "{tag}"')
return borgmatic.hooks.dispatch.call_hook('load_credential', {}, hook_name, credential_name)
return tag

View file

@ -5,7 +5,7 @@ import shlex
import borgmatic.borg.pattern
import borgmatic.config.paths
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
from borgmatic.execute import (
execute_command,
execute_command_and_capture_output,
@ -47,7 +47,7 @@ def database_names_to_dump(database, extra_environment, dry_run):
+ (('--port', str(database['port'])) if 'port' in database else ())
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
+ (
('--user', borgmatic.hooks.credential.tag.resolve_credential(database['username']))
('--user', borgmatic.hooks.credential.parse.resolve_credential(database['username']))
if 'username' in database
else ()
)
@ -102,7 +102,7 @@ def execute_dump_command(
+ (('--port', str(database['port'])) if 'port' in database else ())
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
+ (
('--user', borgmatic.hooks.credential.tag.resolve_credential(database['username']))
('--user', borgmatic.hooks.credential.parse.resolve_credential(database['username']))
if 'username' in database
else ()
)
@ -162,7 +162,7 @@ def dump_data_sources(
for database in databases:
dump_path = make_dump_path(borgmatic_runtime_directory)
extra_environment = (
{'MYSQL_PWD': borgmatic.hooks.credential.tag.resolve_credential(database['password'])}
{'MYSQL_PWD': borgmatic.hooks.credential.parse.resolve_credential(database['password'])}
if 'password' in database
else None
)
@ -264,11 +264,11 @@ def restore_data_source_dump(
port = str(
connection_params['port'] or data_source.get('restore_port', data_source.get('port', ''))
)
username = borgmatic.hooks.credential.tag.resolve_credential(
username = borgmatic.hooks.credential.parse.resolve_credential(
connection_params['username']
or data_source.get('restore_username', data_source.get('username'))
)
password = borgmatic.hooks.credential.tag.resolve_credential(
password = borgmatic.hooks.credential.parse.resolve_credential(
connection_params['password']
or data_source.get('restore_password', data_source.get('password'))
)

View file

@ -4,7 +4,7 @@ import shlex
import borgmatic.borg.pattern
import borgmatic.config.paths
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
from borgmatic.execute import execute_command, execute_command_with_processes
from borgmatic.hooks.data_source import dump
@ -103,7 +103,7 @@ def build_dump_command(database, dump_filename, dump_format):
(
'--username',
shlex.quote(
borgmatic.hooks.credential.tag.resolve_credential(database['username'])
borgmatic.hooks.credential.parse.resolve_credential(database['username'])
),
)
if 'username' in database
@ -113,7 +113,7 @@ def build_dump_command(database, dump_filename, dump_format):
(
'--password',
shlex.quote(
borgmatic.hooks.credential.tag.resolve_credential(database['password'])
borgmatic.hooks.credential.parse.resolve_credential(database['password'])
),
)
if 'password' in database
@ -217,10 +217,10 @@ def build_restore_command(extract_process, database, dump_filename, connection_p
'restore_hostname', database.get('hostname')
)
port = str(connection_params['port'] or database.get('restore_port', database.get('port', '')))
username = borgmatic.hooks.credential.tag.resolve_credential(
username = borgmatic.hooks.credential.parse.resolve_credential(
connection_params['username'] or database.get('restore_username', database.get('username'))
)
password = borgmatic.hooks.credential.tag.resolve_credential(
password = borgmatic.hooks.credential.parse.resolve_credential(
connection_params['password'] or database.get('restore_password', database.get('password'))
)

View file

@ -5,7 +5,7 @@ import shlex
import borgmatic.borg.pattern
import borgmatic.config.paths
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
from borgmatic.execute import (
execute_command,
execute_command_and_capture_output,
@ -47,7 +47,7 @@ def database_names_to_dump(database, extra_environment, dry_run):
+ (('--port', str(database['port'])) if 'port' in database else ())
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
+ (
('--user', borgmatic.hooks.credential.tag.resolve_credential(database['username']))
('--user', borgmatic.hooks.credential.parse.resolve_credential(database['username']))
if 'username' in database
else ()
)
@ -101,7 +101,7 @@ def execute_dump_command(
+ (('--port', str(database['port'])) if 'port' in database else ())
+ (('--protocol', 'tcp') if 'hostname' in database or 'port' in database else ())
+ (
('--user', borgmatic.hooks.credential.tag.resolve_credential(database['username']))
('--user', borgmatic.hooks.credential.parse.resolve_credential(database['username']))
if 'username' in database
else ()
)
@ -161,7 +161,7 @@ def dump_data_sources(
for database in databases:
dump_path = make_dump_path(borgmatic_runtime_directory)
extra_environment = (
{'MYSQL_PWD': borgmatic.hooks.credential.tag.resolve_credential(database['password'])}
{'MYSQL_PWD': borgmatic.hooks.credential.parse.resolve_credential(database['password'])}
if 'password' in database
else None
)
@ -263,11 +263,11 @@ def restore_data_source_dump(
port = str(
connection_params['port'] or data_source.get('restore_port', data_source.get('port', ''))
)
username = borgmatic.hooks.credential.tag.resolve_credential(
username = borgmatic.hooks.credential.parse.resolve_credential(
connection_params['username']
or data_source.get('restore_username', data_source.get('username'))
)
password = borgmatic.hooks.credential.tag.resolve_credential(
password = borgmatic.hooks.credential.parse.resolve_credential(
connection_params['password']
or data_source.get('restore_password', data_source.get('password'))
)

View file

@ -7,7 +7,7 @@ import shlex
import borgmatic.borg.pattern
import borgmatic.config.paths
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
from borgmatic.execute import (
execute_command,
execute_command_and_capture_output,
@ -34,12 +34,12 @@ def make_extra_environment(database, restore_connection_params=None):
try:
if restore_connection_params:
extra['PGPASSWORD'] = borgmatic.hooks.credential.tag.resolve_credential(
extra['PGPASSWORD'] = borgmatic.hooks.credential.parse.resolve_credential(
restore_connection_params.get('password')
or database.get('restore_password', database['password'])
)
else:
extra['PGPASSWORD'] = borgmatic.hooks.credential.tag.resolve_credential(
extra['PGPASSWORD'] = borgmatic.hooks.credential.parse.resolve_credential(
database['password']
)
except (AttributeError, KeyError):
@ -87,7 +87,10 @@ def database_names_to_dump(database, extra_environment, dry_run):
+ (('--host', database['hostname']) if 'hostname' in database else ())
+ (('--port', str(database['port'])) if 'port' in database else ())
+ (
('--username', borgmatic.hooks.credential.tag.resolve_credential(database['username']))
(
'--username',
borgmatic.hooks.credential.parse.resolve_credential(database['username']),
)
if 'username' in database
else ()
)
@ -185,7 +188,9 @@ def dump_data_sources(
(
'--username',
shlex.quote(
borgmatic.hooks.credential.tag.resolve_credential(database['username'])
borgmatic.hooks.credential.parse.resolve_credential(
database['username']
)
),
)
if 'username' in database
@ -303,7 +308,7 @@ def restore_data_source_dump(
port = str(
connection_params['port'] or data_source.get('restore_port', data_source.get('port', ''))
)
username = borgmatic.hooks.credential.tag.resolve_credential(
username = borgmatic.hooks.credential.parse.resolve_credential(
connection_params['username']
or data_source.get('restore_username', data_source.get('username'))
)

View file

@ -2,7 +2,7 @@ import logging
import requests
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
logger = logging.getLogger(__name__)
@ -50,13 +50,13 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
}
try:
username = borgmatic.hooks.credential.tag.resolve_credential(
username = borgmatic.hooks.credential.parse.resolve_credential(
hook_config.get('username')
)
password = borgmatic.hooks.credential.tag.resolve_credential(
password = borgmatic.hooks.credential.parse.resolve_credential(
hook_config.get('password')
)
access_token = borgmatic.hooks.credential.tag.resolve_credential(
access_token = borgmatic.hooks.credential.parse.resolve_credential(
hook_config.get('access_token')
)
except ValueError as error:

View file

@ -5,7 +5,7 @@ import platform
import requests
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
from borgmatic.hooks.monitoring import monitor
logger = logging.getLogger(__name__)
@ -41,7 +41,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
return
try:
integration_key = borgmatic.hooks.credential.tag.resolve_credential(
integration_key = borgmatic.hooks.credential.parse.resolve_credential(
hook_config.get('integration_key')
)
except ValueError as error:

View file

@ -2,7 +2,7 @@ import logging
import requests
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
logger = logging.getLogger(__name__)
@ -35,8 +35,8 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
state_config = hook_config.get(state.name.lower(), {})
try:
token = borgmatic.hooks.credential.tag.resolve_credential(hook_config.get('token'))
user = borgmatic.hooks.credential.tag.resolve_credential(hook_config.get('user'))
token = borgmatic.hooks.credential.parse.resolve_credential(hook_config.get('token'))
user = borgmatic.hooks.credential.parse.resolve_credential(hook_config.get('user'))
except ValueError as error:
logger.warning(f'Pushover credential error: {error}')
return

View file

@ -2,7 +2,7 @@ import logging
import requests
import borgmatic.hooks.credential.tag
import borgmatic.hooks.credential.parse
logger = logging.getLogger(__name__)
@ -37,9 +37,9 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
)
try:
username = borgmatic.hooks.credential.tag.resolve_credential(hook_config.get('username'))
password = borgmatic.hooks.credential.tag.resolve_credential(hook_config.get('password'))
api_key = borgmatic.hooks.credential.tag.resolve_credential(hook_config.get('api_key'))
username = borgmatic.hooks.credential.parse.resolve_credential(hook_config.get('username'))
password = borgmatic.hooks.credential.parse.resolve_credential(hook_config.get('password'))
api_key = borgmatic.hooks.credential.parse.resolve_credential(hook_config.get('api_key'))
except ValueError as error:
logger.warning(f'Zabbix credential error: {error}')
return

View file

@ -62,7 +62,7 @@ systemd-ask-password -n | systemd-creds encrypt - /etc/credstore.encrypted/borgm
Then use the following in your configuration file:
```yaml
encryption_passphrase: !credential systemd borgmatic.pw
encryption_passphrase: "{credential systemd borgmatic.pw}"
```
<span class="minilink minilink-addedin">Prior to version 1.9.10</span> You can
@ -74,16 +74,16 @@ encryption_passcommand: cat ${CREDENTIALS_DIRECTORY}/borgmatic.pw
Note that the name `borgmatic.pw` is hardcoded in the systemd service file.
The `!credential` tag works for several different options in a borgmatic
The `{credential ...}` syntax works for several different options in a borgmatic
configuration file besides just `encryption_passphrase`. For instance, the
username, password, and API token options within database and monitoring hooks
support `!credential`. For example:
support `{credential ...}`:
```yaml
postgresql_databases:
- name: invoices
username: postgres
password: !credential systemd borgmatic_db1
password: "{credential systemd borgmatic_db1}"
```
For specifics about which options are supported, see the
@ -121,7 +121,7 @@ Finally, use something like the following in your borgmatic configuration file
for each option value you'd like to load from systemd:
```yaml
encryption_passphrase: !credential systemd borgmatic_backupserver1
encryption_passphrase: "{credential systemd borgmatic_backupserver1}"
```
<span class="minilink minilink-addedin">Prior to version 1.9.10</span> Use the
@ -135,12 +135,12 @@ encryption_passcommand: cat ${CREDENTIALS_DIRECTORY}/borgmatic_backupserver1
Adjust `borgmatic_backupserver1` according to the name of the credential and the
directory set in the service file.
Be aware that when using this systemd `!credential` feature, you may no longer
be able to run certain borgmatic actions outside of the systemd service, as the
credentials are only available from within the context of that service. So for
instance, `borgmatic list` necessarily relies on the `encryption_passphrase` in
order to access the Borg repository, but it shouldn't need to load any
credentials for your database or monitoring hooks.
Be aware that when using this systemd `{credential ...}` feature, you may no
longer be able to run certain borgmatic actions outside of the systemd service,
as the credentials are only available from within the context of that service.
So for instance, `borgmatic list` necessarily relies on the
`encryption_passphrase` in order to access the Borg repository, but `list`
shouldn't need to load any credentials for your database or monitoring hooks.
The one exception is `borgmatic config validate`, which doesn't actually load
any credentials and should continue working anywhere.

View file

@ -23,7 +23,7 @@ def generate_configuration(config_path, repository_path):
.replace('- /home', f'- {config_path}')
.replace('- /etc', '')
.replace('- /var/log/syslog*', '')
+ '\nencryption_passphrase: !credential systemd mycredential'
+ '\nencryption_passphrase: "{credential systemd mycredential}"'
)
config_file = open(config_path, 'w')
config_file.write(config)

View file

@ -225,20 +225,6 @@ def test_load_configuration_merges_multiple_file_include():
assert config_paths == {'config.yaml', '/tmp/include1.yaml', '/tmp/include2.yaml', 'other.yaml'}
def test_load_configuration_passes_through_credential_tag():
builtins = flexmock(sys.modules['builtins'])
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
flexmock(module.os.path).should_receive('isabs').and_return(False)
flexmock(module.os.path).should_receive('exists').and_return(True)
config_file = io.StringIO('key: !credential foo bar')
config_file.name = 'config.yaml'
builtins.should_receive('open').with_args('config.yaml').and_return(config_file)
config_paths = {'other.yaml'}
assert module.load_configuration('config.yaml', config_paths) == {'key': '!credential foo bar'}
assert config_paths == {'config.yaml', 'other.yaml'}
def test_load_configuration_with_retain_tag_merges_include_but_keeps_local_values():
builtins = flexmock(sys.modules['builtins'])
flexmock(module.os).should_receive('getcwd').and_return('/tmp')

View file

@ -24,7 +24,7 @@ def test_make_environment_with_passphrase_should_set_environment():
).and_return(None)
flexmock(module.os).should_receive('pipe').never()
flexmock(module.os.environ).should_receive('get').and_return(None)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
@ -39,11 +39,11 @@ def test_make_environment_with_credential_tag_passphrase_should_load_it_and_set_
).and_return(None)
flexmock(module.os).should_receive('pipe').never()
flexmock(module.os.environ).should_receive('get').and_return(None)
flexmock(module.borgmatic.hooks.credential.tag).should_receive('resolve_credential').with_args(
'!credential systemd pass'
).and_return('pass')
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).with_args('{credential systemd pass}').and_return('pass')
environment = module.make_environment({'encryption_passphrase': '!credential systemd pass'})
environment = module.make_environment({'encryption_passphrase': '{credential systemd pass}'})
assert environment.get('BORG_PASSPHRASE') == 'pass'

View file

@ -43,17 +43,3 @@ def test_probe_and_include_file_with_relative_path_and_missing_files_raises():
with pytest.raises(FileNotFoundError):
module.probe_and_include_file('include.yaml', ['/etc', '/var'], config_paths=set())
def test_reserialize_tag_node_turns_it_into_string():
assert (
module.reserialize_tag_node(loader=flexmock(), tag_node=flexmock(tag='!tag', value='value'))
== '!tag value'
)
def test_reserialize_tag_node_with_invalid_value_raises():
with pytest.raises(ValueError):
assert module.reserialize_tag_node(
loader=flexmock(), tag_node=flexmock(tag='!tag', value=['value'])
)

View file

@ -1,14 +1,14 @@
import pytest
from flexmock import flexmock
from borgmatic.hooks.credential import tag as module
from borgmatic.hooks.credential import parse as module
def test_resolve_credential_passes_through_string_without_credential_tag():
module.resolve_credential.cache_clear()
flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hook').never()
assert module.resolve_credential('!no credentials here') == '!no credentials here'
assert module.resolve_credential('{no credentials here}') == '{no credentials here}'
def test_resolve_credential_passes_through_none():
@ -18,12 +18,13 @@ def test_resolve_credential_passes_through_none():
assert module.resolve_credential(None) is None
def test_resolve_credential_with_invalid_credential_tag_raises():
@pytest.mark.parametrize('invalid_value', ('{credential}', '{credential }', '{credential systemd}'))
def test_resolve_credential_with_invalid_credential_tag_raises(invalid_value):
module.resolve_credential.cache_clear()
flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hook').never()
with pytest.raises(ValueError):
module.resolve_credential('!credential systemd')
module.resolve_credential(invalid_value)
def test_resolve_credential_with_valid_credential_tag_loads_credential():
@ -35,7 +36,7 @@ def test_resolve_credential_with_valid_credential_tag_loads_credential():
'mycredential',
).and_return('result').once()
assert module.resolve_credential('!credential systemd mycredential') == 'result'
assert module.resolve_credential('{credential systemd mycredential}') == 'result'
def test_resolve_credential_caches_credential_after_first_call():
@ -47,5 +48,5 @@ def test_resolve_credential_caches_credential_after_first_call():
'mycredential',
).and_return('result').once()
assert module.resolve_credential('!credential systemd mycredential') == 'result'
assert module.resolve_credential('!credential systemd mycredential') == 'result'
assert module.resolve_credential('{credential systemd mycredential}') == 'result'
assert module.resolve_credential('{credential systemd mycredential}') == 'result'

View file

@ -25,7 +25,7 @@ def test_database_names_to_dump_bails_for_dry_run():
def test_database_names_to_dump_queries_mariadb_for_database_names():
extra_environment = flexmock()
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
@ -53,7 +53,7 @@ def test_dump_data_sources_dumps_each_database():
databases = [{'name': 'foo'}, {'name': 'bar'}]
processes = [flexmock(), flexmock()]
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
@ -87,7 +87,7 @@ def test_dump_data_sources_dumps_with_password():
database = {'name': 'foo', 'username': 'root', 'password': 'trustsome1'}
process = flexmock()
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
@ -117,7 +117,7 @@ def test_dump_data_sources_dumps_all_databases_at_once():
databases = [{'name': 'all'}]
process = flexmock()
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
@ -144,7 +144,7 @@ def test_dump_data_sources_dumps_all_databases_separately_when_format_configured
databases = [{'name': 'all', 'format': 'sql'}]
processes = [flexmock(), flexmock()]
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
@ -214,7 +214,7 @@ def test_execute_dump_command_runs_mariadb_dump():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -249,7 +249,7 @@ def test_execute_dump_command_runs_mariadb_dump_without_add_drop_database():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -283,7 +283,7 @@ def test_execute_dump_command_runs_mariadb_dump_with_hostname_and_port():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -324,7 +324,7 @@ def test_execute_dump_command_runs_mariadb_dump_with_username_and_password():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -361,7 +361,7 @@ def test_execute_dump_command_runs_mariadb_dump_with_options():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -397,7 +397,7 @@ def test_execute_dump_command_runs_non_default_mariadb_dump_with_options():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -455,7 +455,7 @@ def test_execute_dump_command_with_duplicate_dump_skips_mariadb_dump():
def test_execute_dump_command_with_dry_run_skips_mariadb_dump():
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -478,7 +478,7 @@ def test_execute_dump_command_with_dry_run_skips_mariadb_dump():
def test_dump_data_sources_errors_for_missing_all_databases():
databases = [{'name': 'all'}]
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
@ -500,7 +500,7 @@ def test_dump_data_sources_errors_for_missing_all_databases():
def test_dump_data_sources_does_not_error_for_missing_all_databases_with_dry_run():
databases = [{'name': 'all'}]
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
@ -525,7 +525,7 @@ def test_restore_data_source_dump_runs_mariadb_to_restore():
hook_config = [{'name': 'foo'}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -556,7 +556,7 @@ def test_restore_data_source_dump_runs_mariadb_with_options():
hook_config = [{'name': 'foo', 'restore_options': '--harder'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -589,7 +589,7 @@ def test_restore_data_source_dump_runs_non_default_mariadb_with_options():
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -620,7 +620,7 @@ def test_restore_data_source_dump_runs_mariadb_with_hostname_and_port():
hook_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -660,7 +660,7 @@ def test_restore_data_source_dump_runs_mariadb_with_username_and_password():
hook_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -701,7 +701,7 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -755,7 +755,7 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -796,7 +796,7 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
def test_restore_data_source_dump_with_dry_run_skips_restore():
hook_config = [{'name': 'foo'}]
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').never()

View file

@ -124,7 +124,7 @@ def test_dump_data_sources_runs_mongodump_with_username_and_password():
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
'databases/localhost/foo'
)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -245,7 +245,7 @@ def test_dump_data_sources_runs_mongodumpall_for_all_databases():
def test_build_dump_command_with_username_injection_attack_gets_escaped():
database = {'name': 'test', 'username': 'bob; naughty-command'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
@ -260,7 +260,7 @@ def test_restore_data_source_dump_runs_mongorestore():
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -294,7 +294,7 @@ def test_restore_data_source_dump_runs_mongorestore_with_hostname_and_port():
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -342,7 +342,7 @@ def test_restore_data_source_dump_runs_mongorestore_with_username_and_password()
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -396,7 +396,7 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -454,7 +454,7 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -500,7 +500,7 @@ def test_restore_data_source_dump_runs_mongorestore_with_options():
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -532,7 +532,7 @@ def test_restore_databases_dump_runs_mongorestore_with_schemas():
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -572,7 +572,7 @@ def test_restore_data_source_dump_runs_psql_for_all_database_dump():
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -603,7 +603,7 @@ def test_restore_data_source_dump_with_dry_run_skips_restore():
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').never()
@ -629,7 +629,7 @@ def test_restore_data_source_dump_without_extract_process_restores_from_disk():
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('/dump/path')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(

View file

@ -16,7 +16,7 @@ def test_database_names_to_dump_passes_through_name():
def test_database_names_to_dump_bails_for_dry_run():
extra_environment = flexmock()
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').never()
@ -28,7 +28,7 @@ def test_database_names_to_dump_bails_for_dry_run():
def test_database_names_to_dump_queries_mysql_for_database_names():
extra_environment = flexmock()
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
@ -87,7 +87,7 @@ def test_dump_data_sources_dumps_with_password():
database = {'name': 'foo', 'username': 'root', 'password': 'trustsome1'}
process = flexmock()
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
@ -208,7 +208,7 @@ def test_execute_dump_command_runs_mysqldump():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -243,7 +243,7 @@ def test_execute_dump_command_runs_mysqldump_without_add_drop_database():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -277,7 +277,7 @@ def test_execute_dump_command_runs_mysqldump_with_hostname_and_port():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -318,7 +318,7 @@ def test_execute_dump_command_runs_mysqldump_with_username_and_password():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -355,7 +355,7 @@ def test_execute_dump_command_runs_mysqldump_with_options():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -391,7 +391,7 @@ def test_execute_dump_command_runs_non_default_mysqldump():
process = flexmock()
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -447,7 +447,7 @@ def test_execute_dump_command_with_duplicate_dump_skips_mysqldump():
def test_execute_dump_command_with_dry_run_skips_mysqldump():
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -470,7 +470,7 @@ def test_execute_dump_command_with_dry_run_skips_mysqldump():
def test_dump_data_sources_errors_for_missing_all_databases():
databases = [{'name': 'all'}]
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
@ -492,7 +492,7 @@ def test_dump_data_sources_errors_for_missing_all_databases():
def test_dump_data_sources_does_not_error_for_missing_all_databases_with_dry_run():
databases = [{'name': 'all'}]
flexmock(module).should_receive('make_dump_path').and_return('')
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
@ -517,7 +517,7 @@ def test_restore_data_source_dump_runs_mysql_to_restore():
hook_config = [{'name': 'foo'}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -548,7 +548,7 @@ def test_restore_data_source_dump_runs_mysql_with_options():
hook_config = [{'name': 'foo', 'restore_options': '--harder'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -579,7 +579,7 @@ def test_restore_data_source_dump_runs_non_default_mysql_with_options():
hook_config = [{'name': 'foo', 'mysql_command': 'custom_mysql', 'restore_options': '--harder'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -610,7 +610,7 @@ def test_restore_data_source_dump_runs_mysql_with_hostname_and_port():
hook_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -650,7 +650,7 @@ def test_restore_data_source_dump_runs_mysql_with_username_and_password():
hook_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -691,7 +691,7 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -745,7 +745,7 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -786,7 +786,7 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
def test_restore_data_source_dump_with_dry_run_skips_restore():
hook_config = [{'name': 'foo'}]
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_with_processes').never()

View file

@ -24,7 +24,7 @@ def test_make_extra_environment_maps_options_to_environment():
'PGSSLROOTCERT': 'root.crt',
'PGSSLCRL': 'crl.crl',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
@ -35,7 +35,7 @@ def test_make_extra_environment_maps_options_to_environment():
def test_make_extra_environment_with_cli_password_sets_correct_password():
database = {'name': 'foo', 'restore_password': 'trustsome1', 'password': 'anotherpassword'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
@ -84,7 +84,7 @@ def test_database_names_to_dump_passes_through_all_without_format():
def test_database_names_to_dump_with_all_and_format_and_dry_run_bails():
database = {'name': 'all', 'format': 'custom'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').never()
@ -94,7 +94,7 @@ def test_database_names_to_dump_with_all_and_format_and_dry_run_bails():
def test_database_names_to_dump_with_all_and_format_lists_databases():
database = {'name': 'all', 'format': 'custom'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').and_return(
@ -109,7 +109,7 @@ def test_database_names_to_dump_with_all_and_format_lists_databases():
def test_database_names_to_dump_with_all_and_format_lists_databases_with_hostname_and_port():
database = {'name': 'all', 'format': 'custom', 'hostname': 'localhost', 'port': 1234}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
@ -136,7 +136,7 @@ def test_database_names_to_dump_with_all_and_format_lists_databases_with_hostnam
def test_database_names_to_dump_with_all_and_format_lists_databases_with_username():
database = {'name': 'all', 'format': 'custom', 'username': 'postgres'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
@ -161,7 +161,7 @@ def test_database_names_to_dump_with_all_and_format_lists_databases_with_usernam
def test_database_names_to_dump_with_all_and_format_lists_databases_with_options():
database = {'name': 'all', 'format': 'custom', 'list_options': '--harder'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
@ -177,7 +177,7 @@ def test_database_names_to_dump_with_all_and_format_lists_databases_with_options
def test_database_names_to_dump_with_all_and_format_excludes_particular_databases():
database = {'name': 'all', 'format': 'custom'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').and_return(
@ -193,7 +193,7 @@ def test_database_names_to_dump_with_all_and_psql_command_uses_custom_command():
'format': 'custom',
'psql_command': 'docker exec --workdir * mycontainer psql',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('execute_command_and_capture_output').with_args(
@ -246,7 +246,7 @@ def test_dump_data_sources_runs_pg_dump_for_each_database():
'databases/localhost/foo'
).and_return('databases/localhost/bar')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -353,7 +353,7 @@ def test_dump_data_sources_with_dry_run_skips_pg_dump():
'databases/localhost/foo'
).and_return('databases/localhost/bar')
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
@ -382,7 +382,7 @@ def test_dump_data_sources_runs_pg_dump_with_hostname_and_port():
'databases/database.example.org/foo'
)
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -430,7 +430,7 @@ def test_dump_data_sources_runs_pg_dump_with_username_and_password():
'databases/localhost/foo'
)
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -476,7 +476,7 @@ def test_dump_data_sources_with_username_injection_attack_gets_escaped():
'databases/localhost/foo'
)
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -519,7 +519,7 @@ def test_dump_data_sources_runs_pg_dump_with_directory_format():
'databases/localhost/foo'
)
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_parent_directory_for_dump')
@ -564,7 +564,7 @@ def test_dump_data_sources_runs_pg_dump_with_options():
'databases/localhost/foo'
)
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -607,7 +607,7 @@ def test_dump_data_sources_runs_pg_dumpall_for_all_databases():
'databases/localhost/all'
)
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -639,7 +639,7 @@ def test_dump_data_sources_runs_non_default_pg_dump():
'databases/localhost/foo'
)
flexmock(module.os.path).should_receive('exists').and_return(False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.dump).should_receive('create_named_pipe_for_dump')
@ -677,7 +677,7 @@ def test_restore_data_source_dump_runs_pg_restore():
hook_config = [{'name': 'foo', 'schemas': None}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -734,7 +734,7 @@ def test_restore_data_source_dump_runs_pg_restore_with_hostname_and_port():
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -799,7 +799,7 @@ def test_restore_data_source_dump_runs_pg_restore_with_username_and_password():
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return(
@ -873,7 +873,7 @@ def test_restore_data_source_dump_with_connection_params_uses_connection_params_
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return(
@ -955,7 +955,7 @@ def test_restore_data_source_dump_without_connection_params_uses_restore_params_
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return(
@ -1031,7 +1031,7 @@ def test_restore_data_source_dump_runs_pg_restore_with_options():
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -1088,7 +1088,7 @@ def test_restore_data_source_dump_runs_psql_for_all_database_dump():
hook_config = [{'name': 'all', 'schemas': None}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -1130,7 +1130,7 @@ def test_restore_data_source_dump_runs_psql_for_plain_database_dump():
hook_config = [{'name': 'foo', 'format': 'plain', 'schemas': None}]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -1184,7 +1184,7 @@ def test_restore_data_source_dump_runs_non_default_pg_restore_and_psql():
]
extract_process = flexmock(stdout=flexmock())
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -1248,7 +1248,7 @@ def test_restore_data_source_dump_runs_non_default_pg_restore_and_psql():
def test_restore_data_source_dump_with_dry_run_skips_restore():
hook_config = [{'name': 'foo', 'schemas': None}]
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -1275,7 +1275,7 @@ def test_restore_data_source_dump_with_dry_run_skips_restore():
def test_restore_data_source_dump_without_extract_process_restores_from_disk():
hook_config = [{'name': 'foo', 'schemas': None}]
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -1330,7 +1330,7 @@ def test_restore_data_source_dump_without_extract_process_restores_from_disk():
def test_restore_data_source_dump_with_schemas_restores_schemas():
hook_config = [{'name': 'foo', 'schemas': ['bar', 'baz']}]
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})

View file

@ -36,7 +36,7 @@ def return_default_message_headers(state=Enum):
def test_ping_monitor_minimal_config_hits_hosted_ntfy_on_fail():
hook_config = {'topic': topic}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -60,7 +60,7 @@ def test_ping_monitor_with_access_token_hits_hosted_ntfy_on_fail():
'topic': topic,
'access_token': 'abc123',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -86,7 +86,7 @@ def test_ping_monitor_with_username_password_and_access_token_ignores_username_p
'password': 'fakepassword',
'access_token': 'abc123',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -112,7 +112,7 @@ def test_ping_monitor_with_username_password_hits_hosted_ntfy_on_fail():
'username': 'testuser',
'password': 'fakepassword',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -133,7 +133,7 @@ def test_ping_monitor_with_username_password_hits_hosted_ntfy_on_fail():
def test_ping_monitor_with_password_but_no_username_warns():
hook_config = {'topic': topic, 'password': 'fakepassword'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -155,7 +155,7 @@ def test_ping_monitor_with_password_but_no_username_warns():
def test_ping_monitor_with_username_but_no_password_warns():
hook_config = {'topic': topic, 'username': 'testuser'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -177,7 +177,7 @@ def test_ping_monitor_with_username_but_no_password_warns():
def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_start():
hook_config = {'topic': topic}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').never()
@ -194,7 +194,7 @@ def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_start():
def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_finish():
hook_config = {'topic': topic}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').never()
@ -211,7 +211,7 @@ def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_finish():
def test_ping_monitor_minimal_config_hits_selfhosted_ntfy_on_fail():
hook_config = {'topic': topic, 'server': custom_base_url}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -232,7 +232,7 @@ def test_ping_monitor_minimal_config_hits_selfhosted_ntfy_on_fail():
def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_fail_dry_run():
hook_config = {'topic': topic}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').never()
@ -249,7 +249,7 @@ def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_fail_dry_run():
def test_ping_monitor_custom_message_hits_hosted_ntfy_on_fail():
hook_config = {'topic': topic, 'fail': custom_message_config}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -268,7 +268,7 @@ def test_ping_monitor_custom_message_hits_hosted_ntfy_on_fail():
def test_ping_monitor_custom_state_hits_hosted_ntfy_on_start():
hook_config = {'topic': topic, 'states': ['start', 'fail']}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -289,7 +289,7 @@ def test_ping_monitor_custom_state_hits_hosted_ntfy_on_start():
def test_ping_monitor_with_connection_error_logs_warning():
hook_config = {'topic': topic}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -311,9 +311,9 @@ def test_ping_monitor_with_connection_error_logs_warning():
def test_ping_monitor_with_credential_error_logs_warning():
hook_config = {'topic': topic}
flexmock(module.borgmatic.hooks.credential.tag).should_receive('resolve_credential').and_raise(
ValueError
)
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).and_raise(ValueError)
flexmock(module.requests).should_receive('post').never()
flexmock(module.logger).should_receive('warning').once()
@ -329,7 +329,7 @@ def test_ping_monitor_with_credential_error_logs_warning():
def test_ping_monitor_with_other_error_logs_warning():
hook_config = {'topic': topic}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
response = flexmock(ok=False)

View file

@ -4,7 +4,7 @@ from borgmatic.hooks.monitoring import pagerduty as module
def test_ping_monitor_ignores_start_state():
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').never()
@ -20,7 +20,7 @@ def test_ping_monitor_ignores_start_state():
def test_ping_monitor_ignores_finish_state():
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').never()
@ -36,7 +36,7 @@ def test_ping_monitor_ignores_finish_state():
def test_ping_monitor_calls_api_for_fail_state():
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').and_return(flexmock(ok=True))
@ -52,7 +52,7 @@ def test_ping_monitor_calls_api_for_fail_state():
def test_ping_monitor_dry_run_does_not_call_api():
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').never()
@ -68,7 +68,7 @@ def test_ping_monitor_dry_run_does_not_call_api():
def test_ping_monitor_with_connection_error_logs_warning():
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').and_raise(
@ -87,9 +87,9 @@ def test_ping_monitor_with_connection_error_logs_warning():
def test_ping_monitor_with_credential_error_logs_warning():
flexmock(module.borgmatic.hooks.credential.tag).should_receive('resolve_credential').and_raise(
ValueError
)
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).and_raise(ValueError)
flexmock(module.requests).should_receive('post').never()
flexmock(module.logger).should_receive('warning')
@ -105,7 +105,7 @@ def test_ping_monitor_with_credential_error_logs_warning():
def test_ping_monitor_with_other_error_logs_warning():
response = flexmock(ok=False)
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
response.should_receive('raise_for_status').and_raise(

View file

@ -11,7 +11,7 @@ def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_
should be auto populated with the default value which is the state name.
'''
hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -41,7 +41,7 @@ def test_ping_monitor_config_with_minimum_config_start_state_backup_not_send_to_
'start' state. Only the 'fail' state is enabled by default.
'''
hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -69,7 +69,7 @@ def test_ping_monitor_start_state_backup_default_message_successfully_send_to_pu
'user': '983hfe0of902lkjfa2amanfgui',
'states': {'start', 'fail', 'finish'},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -105,7 +105,7 @@ def test_ping_monitor_start_state_backup_custom_message_successfully_send_to_pus
'states': {'start', 'fail', 'finish'},
'start': {'message': 'custom start message'},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -140,7 +140,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency
'states': {'start', 'fail', 'finish'},
'start': {'priority': 2},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -178,7 +178,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency
'states': {'start', 'fail', 'finish'},
'start': {'priority': 2, 'expire': 600},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -216,7 +216,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_emergency
'states': {'start', 'fail', 'finish'},
'start': {'priority': 2, 'retry': 30},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -257,7 +257,7 @@ def test_ping_monitor_start_state_backup_default_message_with_priority_high_decl
'start': {'priority': 1, 'expire': 30, 'retry': 30},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -312,7 +312,7 @@ def test_ping_monitor_start_state_backup_based_on_documentation_advanced_example
'url_title': 'Login to ticketing system',
},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -378,7 +378,7 @@ def test_ping_monitor_fail_state_backup_based_on_documentation_advanced_example_
'url_title': 'Login to ticketing system',
},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -449,7 +449,7 @@ def test_ping_monitor_finish_state_backup_based_on_documentation_advanced_exampl
'url_title': 'Login to ticketing system',
},
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -485,7 +485,7 @@ def test_ping_monitor_config_with_minimum_config_fail_state_backup_successfully_
should be auto populated with the default value which is the state name.
'''
hook_config = {'token': 'ksdjfwoweijfvwoeifvjmwghagy92', 'user': '983hfe0of902lkjfa2amanfgui'}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -509,7 +509,7 @@ def test_ping_monitor_config_incorrect_state_exit_early():
'token': 'ksdjfwoweijfvwoeifvjmwghagy92',
'user': '983hfe0of902lkjfa2amanfgui',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').never()
@ -535,7 +535,7 @@ def test_ping_monitor_push_post_error_bails():
'user': '983hfe0of902lkjfa2amanfgui',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
push_response = flexmock(ok=False)
@ -570,9 +570,9 @@ def test_ping_monitor_credential_error_bails():
'user': '983hfe0of902lkjfa2amanfgui',
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive('resolve_credential').and_raise(
ValueError
)
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).and_raise(ValueError)
flexmock(module.requests).should_receive('post').never()
flexmock(module.logger).should_receive('warning').once()

View file

@ -75,7 +75,7 @@ def test_ping_monitor_config_with_api_key_only_bails():
# This test should exit early since only providing an API KEY is not enough
# for the hook to work
hook_config = {'api_key': API_KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -95,7 +95,7 @@ def test_ping_monitor_config_with_host_only_bails():
# This test should exit early since only providing a HOST is not enough
# for the hook to work
hook_config = {'host': HOST}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -115,7 +115,7 @@ def test_ping_monitor_config_with_key_only_bails():
# This test should exit early since only providing a KEY is not enough
# for the hook to work
hook_config = {'key': KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -135,7 +135,7 @@ def test_ping_monitor_config_with_server_only_bails():
# This test should exit early since only providing a SERVER is not enough
# for the hook to work
hook_config = {'server': SERVER}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -154,7 +154,7 @@ def test_ping_monitor_config_with_server_only_bails():
def test_ping_monitor_config_user_password_no_zabbix_data_bails():
# This test should exit early since there are HOST/KEY or ITEMID provided to publish data to
hook_config = {'server': SERVER, 'username': USERNAME, 'password': PASSWORD}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -173,7 +173,7 @@ def test_ping_monitor_config_user_password_no_zabbix_data_bails():
def test_ping_monitor_config_api_key_no_zabbix_data_bails():
# This test should exit early since there are HOST/KEY or ITEMID provided to publish data to
hook_config = {'server': SERVER, 'api_key': API_KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -193,7 +193,7 @@ def test_ping_monitor_config_itemid_no_auth_data_bails():
# This test should exit early since there is no authentication provided
# and Zabbix requires authentication to use it's API
hook_config = {'server': SERVER, 'itemid': ITEMID}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -213,7 +213,7 @@ def test_ping_monitor_config_host_and_key_no_auth_data_bails():
# This test should exit early since there is no authentication provided
# and Zabbix requires authentication to use it's API
hook_config = {'server': SERVER, 'host': HOST, 'key': KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -233,7 +233,7 @@ def test_ping_monitor_config_host_and_key_with_api_key_auth_data_successful():
# This test should simulate a successful POST to a Zabbix server. This test uses API_KEY
# to authenticate and HOST/KEY to know which item to populate in Zabbix.
hook_config = {'server': SERVER, 'host': HOST, 'key': KEY, 'api_key': API_KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -255,7 +255,7 @@ def test_ping_monitor_config_host_and_key_with_api_key_auth_data_successful():
def test_ping_monitor_config_host_and_missing_key_bails():
hook_config = {'server': SERVER, 'host': HOST, 'api_key': API_KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -273,7 +273,7 @@ def test_ping_monitor_config_host_and_missing_key_bails():
def test_ping_monitor_config_key_and_missing_host_bails():
hook_config = {'server': SERVER, 'key': KEY, 'api_key': API_KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -300,7 +300,7 @@ def test_ping_monitor_config_host_and_key_with_username_password_auth_data_succe
'password': PASSWORD,
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
auth_response = flexmock(ok=True)
@ -341,7 +341,7 @@ def test_ping_monitor_config_host_and_key_with_username_password_auth_data_and_a
'password': PASSWORD,
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
auth_response = flexmock(ok=False)
@ -382,7 +382,7 @@ def test_ping_monitor_config_host_and_key_with_username_and_missing_password_bai
'username': USERNAME,
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -406,7 +406,7 @@ def test_ping_monitor_config_host_and_key_with_password_and_missing_username_bai
'password': PASSWORD,
}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.logger).should_receive('warning').once()
@ -426,7 +426,7 @@ def test_ping_monitor_config_itemid_with_api_key_auth_data_successful():
# This test should simulate a successful POST to a Zabbix server. This test uses API_KEY
# to authenticate and HOST/KEY to know which item to populate in Zabbix.
hook_config = {'server': SERVER, 'itemid': ITEMID, 'api_key': API_KEY}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
flexmock(module.requests).should_receive('post').with_args(
@ -451,7 +451,7 @@ def test_ping_monitor_config_itemid_with_username_password_auth_data_successful(
# to authenticate and HOST/KEY to know which item to populate in Zabbix.
hook_config = {'server': SERVER, 'itemid': ITEMID, 'username': USERNAME, 'password': PASSWORD}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
auth_response = flexmock(ok=True)
@ -486,7 +486,7 @@ def test_ping_monitor_config_itemid_with_username_password_auth_data_successful(
def test_ping_monitor_config_itemid_with_username_password_auth_data_and_push_post_error_bails():
hook_config = {'server': SERVER, 'itemid': ITEMID, 'username': USERNAME, 'password': PASSWORD}
flexmock(module.borgmatic.hooks.credential.tag).should_receive(
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).replace_with(lambda value: value)
auth_response = flexmock(ok=True)
@ -525,9 +525,9 @@ def test_ping_monitor_config_itemid_with_username_password_auth_data_and_push_po
def test_ping_monitor_with_credential_error_bails():
hook_config = {'server': SERVER, 'itemid': ITEMID, 'username': USERNAME, 'password': PASSWORD}
flexmock(module.borgmatic.hooks.credential.tag).should_receive('resolve_credential').and_raise(
ValueError
)
flexmock(module.borgmatic.hooks.credential.parse).should_receive(
'resolve_credential'
).and_raise(ValueError)
flexmock(module.requests).should_receive('post').never()
flexmock(module.logger).should_receive('warning').once()