netbox-community / netbox

The premier source of truth powering network automation. Open source under Apache 2. Try NetBox Cloud free: https://netboxlabs.com/free-netbox-cloud/
http://netboxlabs.com/oss/netbox/
Apache License 2.0
15.79k stars 2.54k forks source link

Implement a mechanism to mark QuerySets as read-only (for template rendering) #12898

Open jeremystretch opened 1 year ago

jeremystretch commented 1 year ago

NetBox version

v3.5.3

Feature type

New functionality

Proposed functionality

Provide a mechanism to disable all write operations of a QuerySet, such that it can be considered safe to use within e.g. an export template. This proposal derived from discussion in #12204.

Per [my comment]() on that issue, a potential solution might be to effect a read_only attribute on the base QuerySet class. If true, any attempt to call a write method (e.g. update() or delete() you raise an exception.

class RestrictedQuerySet(QuerySet):
    read_only = False

    def __setattr__(self, key, value):
        if key == '_for_write' and self.read_only:
            raise Exception('Queryset is read-only!')
        if key == 'read_only' and not value and self.read_only:
            raise Exception('Cannot unmark a read-only queryset')
        return super().__setattr__(key, value)

    def _clone(self):
        c = super()._clone()
        c.read_only = self.read_only
        return c

Setting read_only = True on the queryset triggers an exception whenever a write-enabled method is called:

>>> qs = Site.objects.filter(pk=1)
>>> qs.update(description='foo')
1
>>> qs.read_only = True
>>> qs.update(description='bar')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/db/models/query.py", line 1171, in update
    self._for_write = True
  File "/opt/netbox/netbox/utilities/querysets.py", line 38, in __setattr__
    raise Exception('Queryset is read-only!')
Exception: Queryset is read-only!
>>> qs.read_only = False
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/opt/netbox/netbox/utilities/querysets.py", line 40, in __setattr__
    raise Exception('Cannot unmark a read-only queryset')
Exception: Cannot unmark a read-only queryset

Use case

Disabling potentially destructive methods on a queryset renders it safer to invoke within export templates and similar scenarios where user-provided code is being executed.

Database changes

No response

External dependencies

No response

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Do not attempt to circumvent this process by "bumping" the issue; doing so will result in its immediate closure and you may be barred from participating in any future discussions. Please see our contributing guide.