diff --git a/supervisor/supervisor.py b/supervisor/supervisor.py index 0449c56..1f8df0e 100644 --- a/supervisor/supervisor.py +++ b/supervisor/supervisor.py @@ -1070,15 +1070,14 @@ def run_update(tag: str, cfg: dict, notifier: Optional[TelegramNotifier], _notify(notifier, step, 'Skipping signature verification (nightly)') log.warning('Signature verification SKIPPED (nightly)') else: - # TODO: Re-enable signature verification for production - # Currently disabled for development convenience - _notify(notifier, step, 'Skipping signature verification (dev mode)') - if False: # was: if not skip_verify: + if not skip_verify: + _notify(notifier, step, f'Verifying signature for {tag}') ok, out = verify_tag(app_root, tag) if not ok: raise UpdateError(f'Signature verification failed: {out}') else: - log.warning('Signature verification SKIPPED (dev mode)') + _notify(notifier, step, 'Skipping signature verification (--force)') + log.warning('Signature verification SKIPPED (--force)') # Step 3: Stage (worktree + venv + shared links) step = 3 diff --git a/unit_tests/test_supervisor/test_lifecycle.py b/unit_tests/test_supervisor/test_lifecycle.py index f577608..94f928c 100644 --- a/unit_tests/test_supervisor/test_lifecycle.py +++ b/unit_tests/test_supervisor/test_lifecycle.py @@ -62,8 +62,7 @@ def test_happy_path(self, mock_preflight, mock_current, mock_verify, mock_worktr result = sup.run_update('v1.1.0', self.cfg, None) self.assertTrue(result) - # verify_tag is currently skipped in dev mode (gated by `if False`) - mock_verify.assert_not_called() + mock_verify.assert_called_once_with(self.tmp, 'v1.1.0') mock_worktree.assert_called_once() mock_venv.assert_called_once() mock_health_temp.assert_called_once() @@ -157,6 +156,29 @@ def test_fails_at_start_triggers_rollback(self, mock_preflight, mock_cur, mock_v self.assertFalse(result) mock_rollback.assert_called_once() + @patch.object(sup, '_is_process_alive', return_value=True) + @patch.object(sup, 'start_daemon', return_value=(True, 1234)) + @patch.object(sup, 'stop_daemon', return_value=True) + @patch.object(sup, 'health_check', return_value=True) + @patch.object(sup, 'health_check_temp_port', return_value=True) + @patch.object(sup, 'link_shared_dirs') + @patch.object(sup, 'create_venv_and_install', return_value=(True, '')) + @patch.object(sup, 'create_worktree', return_value=(True, '')) + @patch.object(sup, 'verify_tag', return_value=(True, 'Good signature')) + @patch.object(sup, 'get_current_release', return_value='v1.0.0') + @patch.object(sup, 'preflight_checks', return_value=(True, [])) + def test_skip_verify_skips_signature_check(self, mock_preflight, mock_current, mock_verify, + mock_worktree, mock_venv, mock_link, + mock_health_temp, mock_health, + mock_stop, mock_start, mock_alive): + release_path = os.path.join(self.tmp, 'releases', 'v1.1.0') + os.makedirs(release_path) + + result = sup.run_update('v1.1.0', self.cfg, None, skip_verify=True) + + self.assertTrue(result) + mock_verify.assert_not_called() + class TestCleanupOldReleases(unittest.TestCase): def setUp(self):