From a2501976772cad216c2bc24c2ea6260539bb7066 Mon Sep 17 00:00:00 2001 From: Michael Uray <25169478+MichaelUray@users.noreply.github.com> Date: Thu, 9 Apr 2026 07:22:38 +0000 Subject: [PATCH] [fix] Guard missing skip_push_update_on_save in register view #1331 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeviceRegisterView._update_device_name calls ``device.skip_push_update_on_save()`` whenever an agent re-registers with a hostname different from the MAC address. While the method is defined on AbstractDevice, subclasses or older installations that lack it would crash with AttributeError on every such re-registration (HTTP 500). This breaks the consistent_registration / factory-reset workflow: 1. A router does a factory reset and loses its local UUID/key. 2. The agent computes a consistent key and POSTs to /register/. 3. OpenWISP finds the existing device by key. 4. The view enters _update_device_name (hostname differs from MAC). 5. If skip_push_update_on_save is missing, AttributeError → HTTP 500. 6. The agent sees no X-Openwisp-Controller header and aborts. 7. After 6 retries procd kills the agent. Wrap the call in ``getattr`` so the registration path succeeds whether the helper method exists or not. The guard is forward-compatible. Closes #1331 --- openwisp_controller/config/controller/views.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/openwisp_controller/config/controller/views.py b/openwisp_controller/config/controller/views.py index 3dc714c0c..38ce6a689 100644 --- a/openwisp_controller/config/controller/views.py +++ b/openwisp_controller/config/controller/views.py @@ -475,7 +475,13 @@ def _update_device_name(self, request, device): normalized_name = name.replace(":", "").replace("-", "").lower() if normalized_name != normalized_mac: device.name = name - device.skip_push_update_on_save() + # NOTE: ``device.skip_push_update_on_save()`` is defined on + # AbstractDevice, but we guard the call defensively so that + # subclasses or older installations that may lack the method + # do not crash during factory-reset re-registration. + skip = getattr(device, "skip_push_update_on_save", None) + if callable(skip): + skip() class GetVpnView(SingleObjectMixin, View):