From 5c6407047ff7d07b4d05b4cd5bff587ab4e4b8a2 Mon Sep 17 00:00:00 2001 From: Uli Date: Sat, 23 Jul 2022 22:07:06 +0200 Subject: [PATCH] feat: add verify_tls flag for Healthchecks --- borgmatic/config/schema.yaml | 6 ++++ borgmatic/hooks/healthchecks.py | 4 ++- tests/unit/hooks/test_healthchecks.py | 50 +++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 02caf7929..1880778c9 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1012,6 +1012,12 @@ properties: Healthchecks ping URL or UUID to notify when a backup begins, ends, or errors. example: https://hc-ping.com/your-uuid-here + verify_tls: + type: boolean + description: | + Verify the SSL certificate of the endpoint. + Defaults to true. + example: false send_logs: type: boolean description: | diff --git a/borgmatic/hooks/healthchecks.py b/borgmatic/hooks/healthchecks.py index c801f1824..03d012a8f 100644 --- a/borgmatic/hooks/healthchecks.py +++ b/borgmatic/hooks/healthchecks.py @@ -125,7 +125,9 @@ def ping_monitor(hook_config, config_filename, state, monitoring_log_level, dry_ if not dry_run: logging.getLogger('urllib3').setLevel(logging.ERROR) try: - response = requests.post(ping_url, data=payload.encode('utf-8')) + response = requests.post( + ping_url, data=payload.encode('utf-8'), verify=hook_config.get('verify_tls', True) + ) if not response.ok: response.raise_for_status() except requests.exceptions.RequestException as error: diff --git a/tests/unit/hooks/test_healthchecks.py b/tests/unit/hooks/test_healthchecks.py index 65c5613d3..ee78e52b3 100644 --- a/tests/unit/hooks/test_healthchecks.py +++ b/tests/unit/hooks/test_healthchecks.py @@ -138,7 +138,7 @@ def test_ping_monitor_hits_ping_url_for_start_state(): flexmock(module).should_receive('Forgetful_buffering_handler') hook_config = {'ping_url': 'https://example.com'} flexmock(module.requests).should_receive('post').with_args( - 'https://example.com/start', data=''.encode('utf-8') + 'https://example.com/start', data=''.encode('utf-8'), verify=True ).and_return(flexmock(ok=True)) module.ping_monitor( @@ -155,7 +155,7 @@ def test_ping_monitor_hits_ping_url_for_finish_state(): payload = 'data' flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload) flexmock(module.requests).should_receive('post').with_args( - 'https://example.com', data=payload.encode('utf-8') + 'https://example.com', data=payload.encode('utf-8'), verify=True ).and_return(flexmock(ok=True)) module.ping_monitor( @@ -172,7 +172,7 @@ def test_ping_monitor_hits_ping_url_for_fail_state(): payload = 'data' flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload) flexmock(module.requests).should_receive('post').with_args( - 'https://example.com/fail', data=payload.encode('utf') + 'https://example.com/fail', data=payload.encode('utf'), verify=True ).and_return(flexmock(ok=True)) module.ping_monitor( @@ -189,7 +189,43 @@ def test_ping_monitor_with_ping_uuid_hits_corresponding_url(): payload = 'data' flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload) flexmock(module.requests).should_receive('post').with_args( - 'https://hc-ping.com/{}'.format(hook_config['ping_url']), data=payload.encode('utf-8') + 'https://hc-ping.com/{}'.format(hook_config['ping_url']), + data=payload.encode('utf-8'), + verify=True, + ).and_return(flexmock(ok=True)) + + module.ping_monitor( + hook_config, + 'config.yaml', + state=module.monitor.State.FINISH, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_skips_ssl_verification_when_verify_tls_false(): + hook_config = {'ping_url': 'https://example.com', 'verify_tls': False} + payload = 'data' + flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload) + flexmock(module.requests).should_receive('post').with_args( + 'https://example.com', data=payload.encode('utf-8'), verify=False + ).and_return(flexmock(ok=True)) + + module.ping_monitor( + hook_config, + 'config.yaml', + state=module.monitor.State.FINISH, + monitoring_log_level=1, + dry_run=False, + ) + + +def test_ping_monitor_executes_ssl_verification_when_verify_tls_true(): + hook_config = {'ping_url': 'https://example.com', 'verify_tls': True} + payload = 'data' + flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload) + flexmock(module.requests).should_receive('post').with_args( + 'https://example.com', data=payload.encode('utf-8'), verify=True ).and_return(flexmock(ok=True)) module.ping_monitor( @@ -233,7 +269,7 @@ def test_ping_monitor_hits_ping_url_when_states_matching(): flexmock(module).should_receive('Forgetful_buffering_handler') hook_config = {'ping_url': 'https://example.com', 'states': ['start', 'finish']} flexmock(module.requests).should_receive('post').with_args( - 'https://example.com/start', data=''.encode('utf-8') + 'https://example.com/start', data=''.encode('utf-8'), verify=True ).and_return(flexmock(ok=True)) module.ping_monitor( @@ -249,7 +285,7 @@ def test_ping_monitor_with_connection_error_logs_warning(): flexmock(module).should_receive('Forgetful_buffering_handler') hook_config = {'ping_url': 'https://example.com'} flexmock(module.requests).should_receive('post').with_args( - 'https://example.com/start', data=''.encode('utf-8') + 'https://example.com/start', data=''.encode('utf-8'), verify=True ).and_raise(module.requests.exceptions.ConnectionError) flexmock(module.logger).should_receive('warning').once() @@ -270,7 +306,7 @@ def test_ping_monitor_with_other_error_logs_warning(): module.requests.exceptions.RequestException ) flexmock(module.requests).should_receive('post').with_args( - 'https://example.com/start', data=''.encode('utf-8') + 'https://example.com/start', data=''.encode('utf-8'), verify=True ).and_return(response) flexmock(module.logger).should_receive('warning').once()