Browse Source

Revamp systemd credential syntax to be more consistent with constants (#966).

Dan Helfman 3 months ago
parent
commit
50096296da

+ 2 - 2
NEWS

@@ -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

+ 2 - 2
borgmatic/borg/environment.py

@@ -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)

+ 0 - 16
borgmatic/config/load.py

@@ -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.

+ 35 - 29
borgmatic/config/schema.yaml

@@ -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

+ 42 - 0
borgmatic/hooks/credential/parse.py

@@ -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

+ 0 - 27
borgmatic/hooks/credential/tag.py

@@ -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

+ 6 - 6
borgmatic/hooks/data_source/mariadb.py

@@ -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'))
     )

+ 5 - 5
borgmatic/hooks/data_source/mongodb.py

@@ -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'))
     )
 

+ 6 - 6
borgmatic/hooks/data_source/mysql.py

@@ -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'))
     )

+ 11 - 6
borgmatic/hooks/data_source/postgresql.py

@@ -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'))
     )

+ 4 - 4
borgmatic/hooks/monitoring/ntfy.py

@@ -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:

+ 2 - 2
borgmatic/hooks/monitoring/pagerduty.py

@@ -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:

+ 3 - 3
borgmatic/hooks/monitoring/pushover.py

@@ -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

+ 4 - 4
borgmatic/hooks/monitoring/zabbix.py

@@ -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

+ 11 - 11
docs/how-to/provide-your-passwords.md

@@ -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.

+ 1 - 1
tests/end-to-end/hooks/credential/test_systemd.py

@@ -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)

+ 0 - 14
tests/integration/config/test_load.py

@@ -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')

+ 5 - 5
tests/unit/borg/test_environment.py

@@ -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'
 

+ 0 - 14
tests/unit/config/test_load.py

@@ -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'])
-        )

+ 8 - 7
tests/unit/hooks/credential/test_tag.py → tests/unit/hooks/credential/test_parse.py

@@ -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'

+ 22 - 22
tests/unit/hooks/data_source/test_mariadb.py

@@ -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()

+ 12 - 12
tests/unit/hooks/data_source/test_mongodb.py

@@ -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(

+ 20 - 20
tests/unit/hooks/data_source/test_mysql.py

@@ -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()

+ 30 - 30
tests/unit/hooks/data_source/test_postgresql.py

@@ -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'})

+ 17 - 17
tests/unit/hooks/monitoring/test_ntfy.py

@@ -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)

+ 9 - 9
tests/unit/hooks/monitoring/test_pagerduty.py

@@ -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(

+ 17 - 17
tests/unit/hooks/monitoring/test_pushover.py

@@ -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()
 

+ 21 - 21
tests/unit/hooks/monitoring/test_zabbix.py

@@ -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()