From d433a285243821507757a5985394029005160fa1 Mon Sep 17 00:00:00 2001 From: Martin Hauser Date: Sat, 25 Oct 2025 17:22:03 +0200 Subject: [PATCH] Fixes #20646: Prevent cables from connecting to marked objects (#20678) --- netbox/dcim/models/cables.py | 17 ++++++++++++++--- netbox/dcim/tests/test_models.py | 12 ++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index 89c9a99b4..73ea08ff4 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -393,6 +393,17 @@ class CableTermination(ChangeLoggedModel): def clean(self): super().clean() + # Disallow connecting a cable to any termination object that is + # explicitly flagged as "mark connected". + termination = getattr(self, 'termination', None) + if termination is not None and getattr(termination, "mark_connected", False): + raise ValidationError( + _("Cannot connect a cable to {obj_parent} > {obj} because it is marked as connected.").format( + obj_parent=termination.parent_object, + obj=termination, + ) + ) + # Check for existing termination qs = CableTermination.objects.filter( termination_type=self.termination_type, @@ -404,14 +415,14 @@ class CableTermination(ChangeLoggedModel): existing_termination = qs.first() if existing_termination is not None: raise ValidationError( - _("Duplicate termination found for {app_label}.{model} {termination_id}: cable {cable_pk}".format( + _("Duplicate termination found for {app_label}.{model} {termination_id}: cable {cable_pk}").format( app_label=self.termination_type.app_label, model=self.termination_type.model, termination_id=self.termination_id, cable_pk=existing_termination.cable.pk - )) + ) ) - # Validate interface type (if applicable) + # Validate the interface type (if applicable) if self.termination_type.model == 'interface' and self.termination.type in NONCONNECTABLE_IFACE_TYPES: raise ValidationError( _("Cables cannot be terminated to {type_display} interfaces").format( diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index be9f067d4..676030a04 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -967,6 +967,18 @@ class CableTestCase(TestCase): with self.assertRaises(ValidationError): cable.clean() + def test_cannot_cable_to_mark_connected(self): + """ + Test that a cable cannot be connected to an interface marked as connected. + """ + device1 = Device.objects.get(name='TestDevice1') + interface1 = Interface.objects.get(device__name='TestDevice2', name='eth1') + + mark_connected_interface = Interface(device=device1, name='mark_connected1', mark_connected=True) + cable = Cable(a_terminations=[mark_connected_interface], b_terminations=[interface1]) + with self.assertRaises(ValidationError): + cable.clean() + class VirtualDeviceContextTestCase(TestCase):