diff --git a/auto_backup/models/db_backup.py b/auto_backup/models/db_backup.py index 042038e6183..68878b3d26f 100644 --- a/auto_backup/models/db_backup.py +++ b/auto_backup/models/db_backup.py @@ -84,6 +84,13 @@ class DbBackup(models.Model): help="Path to the private key file. Only the Odoo user should have " "read permissions for that file.", ) + sftp_ignore_hostkey = fields.Boolean( + "Ignore Host Key Verification", + default=False, + help="If enabled, the SFTP connection will not verify the server's " + "host key. This is less secure but useful when the server's host key " + "is not available in the known_hosts file.", + ) backup_format = fields.Selection( [ @@ -278,6 +285,15 @@ def sftp_connection(self): "username": self.sftp_user, "port": self.sftp_port, } + # Optionally disable host key verification + if self.sftp_ignore_hostkey: + cnopts = pysftp.CnOpts() + cnopts.hostkeys = None + params["cnopts"] = cnopts + _logger.warning( + "SFTP host key verification disabled for %s - this is less secure", + self.sftp_host, + ) _logger.debug( "Trying to connect to sftp://%(username)s@%(host)s:%(port)d", extra=params ) diff --git a/auto_backup/tests/test_db_backup.py b/auto_backup/tests/test_db_backup.py index 6ab7236ebfa..1e3aaa35157 100644 --- a/auto_backup/tests/test_db_backup.py +++ b/auto_backup/tests/test_db_backup.py @@ -234,3 +234,29 @@ def test_filename_dump(self): now = datetime.now() res = self.Model.filename(now, ext="dump") self.assertTrue(res.endswith(".dump")) + + @patch(f"{model}.pysftp") + def test_sftp_connection_without_ignore_hostkey(self, mock_pysftp): + """It should NOT pass cnopts when sftp_ignore_hostkey is False""" + rec_id = self.new_record() + rec_id.write({"sftp_ignore_hostkey": False}) + rec_id.sftp_connection() + # Verify cnopts is NOT passed when ignore_hostkey is False + call_kwargs = mock_pysftp.Connection.call_args.kwargs + self.assertNotIn("cnopts", call_kwargs) + + @patch(f"{model}.pysftp") + def test_sftp_connection_with_ignore_hostkey(self, mock_pysftp): + """It should pass cnopts with hostkeys=None when sftp_ignore_hostkey is True""" + rec_id = self.new_record() + rec_id.write({"sftp_ignore_hostkey": True}) + rec_id.sftp_connection() + # Verify cnopts IS passed when ignore_hostkey is True + call_kwargs = mock_pysftp.Connection.call_args.kwargs + self.assertIn("cnopts", call_kwargs) + self.assertIsNone(call_kwargs["cnopts"].hostkeys) + + def test_sftp_ignore_hostkey_default_value(self): + """It should have sftp_ignore_hostkey defaulting to False""" + rec_id = self.new_record() + self.assertFalse(rec_id.sftp_ignore_hostkey) diff --git a/auto_backup/view/db_backup_view.xml b/auto_backup/view/db_backup_view.xml index 036b0a80177..37de96c0c64 100644 --- a/auto_backup/view/db_backup_view.xml +++ b/auto_backup/view/db_backup_view.xml @@ -38,6 +38,7 @@ name="sftp_private_key" placeholder="/home/odoo/.ssh/id_rsa" /> +