nautobot 3.0.3__py3-none-any.whl → 3.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nautobot/core/authentication.py +0 -1
- nautobot/core/celery/schedulers.py +1 -3
- nautobot/core/cli/__init__.py +81 -39
- nautobot/core/settings.yaml +12 -4
- nautobot/core/tests/test_cli.py +120 -1
- nautobot/dcim/forms.py +1 -0
- nautobot/dcim/tables/devices.py +2 -1
- nautobot/dcim/templates/dcim/platform_create.html +3 -4
- nautobot/extras/models/jobs.py +7 -1
- nautobot/extras/signals.py +143 -113
- nautobot/extras/tests/test_utils.py +116 -1
- nautobot/extras/utils.py +18 -16
- nautobot/extras/views.py +2 -14
- nautobot/ipam/apps.py +1 -0
- nautobot/project-static/docs/development/core/release-checklist.html +2 -0
- nautobot/project-static/docs/release-notes/version-3.0.html +235 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +329 -329
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +11 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +11 -4
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +21 -9
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/12-add-tenant-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/12-add-tenant-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/13-assign-tenant-to-device-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/13-assign-tenant-to-device-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/22-create-vlans-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/22-create-vlans-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/23-create-vlans-2-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/23-create-vlans-2-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/24-vlan-main-page-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/24-vlan-main-page-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/25-add-vlan-to-interface-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/25-add-vlan-to-interface-light.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-dark.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-light.png +0 -0
- nautobot/tenancy/tables.py +1 -1
- nautobot/ui/package-lock.json +36 -36
- nautobot/ui/package.json +3 -3
- nautobot/users/models.py +33 -0
- nautobot/users/tests/test_models.py +83 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.4.dist-info}/METADATA +4 -4
- {nautobot-3.0.3.dist-info → nautobot-3.0.4.dist-info}/RECORD +49 -41
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/12-add-tenant.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/13-assign-tenant-to-device.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/14-assign-tenant-to-device-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/22-create-vlans.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/23-create-vlans-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/24-vlan-main-page.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/25-add-vlan-to-interface.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/26-add-vlan-to-interface-2.png +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.4.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.4.dist-info}/NOTICE +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.4.dist-info}/WHEEL +0 -0
- {nautobot-3.0.3.dist-info → nautobot-3.0.4.dist-info}/entry_points.txt +0 -0
|
Binary file
|
|
@@ -17853,8 +17853,8 @@ If not configured, local filesystem storage will be used.</p>
|
|
|
17853
17853
|
<p>For an example of using <code>django-storages</code> with AWS S3 buckets, visit the
|
|
17854
17854
|
<a href="../guides/s3-django-storage.html">django-storages with S3</a> user-guide.</p>
|
|
17855
17855
|
</div>
|
|
17856
|
-
<p>The configuration parameters for the specified storage backend are defined under the
|
|
17857
|
-
<a href="#storage_config"><code>STORAGE_CONFIG</code></a>
|
|
17856
|
+
<p>The configuration parameters for the specified storage backend are defined under the settings
|
|
17857
|
+
<a href="#storage_config"><code>STORAGE_CONFIG</code></a> (deprecated) or <a href="#storages"><code>STORAGES</code></a> (recommended).</p>
|
|
17858
17858
|
<p><strong>See Also:</strong></p>
|
|
17859
17859
|
<ul>
|
|
17860
17860
|
<li><a href="#storages"> <code>STORAGES</code> </a></li>
|
|
@@ -17866,8 +17866,15 @@ If not configured, local filesystem storage will be used.</p>
|
|
|
17866
17866
|
<p>(Deprecated) Dictionary of config parameters for the storage backend configured as STORAGE_BACKEND.</p>
|
|
17867
17867
|
<div class="admonition warning">
|
|
17868
17868
|
<p class="admonition-title">Warning</p>
|
|
17869
|
-
<p>This setting is deprecated and will be removed in Nautobot v3.1.
|
|
17870
|
-
|
|
17869
|
+
<p>This setting is deprecated and will be removed in Nautobot v3.1. In its place, you should set
|
|
17870
|
+
<a href="#storages"><code>STORAGES["default"]["OPTIONS"]</code> and/or <code>STORAGES["staticfiles"]["OPTIONS"]</code></a>.</p>
|
|
17871
|
+
<p>Note that <code>STORAGE_CONFIG</code> is implemented to provide a bit of configuration "magic" that
|
|
17872
|
+
<code>STORAGES["..."]["OPTIONS"]</code> does not; specifically, when <code>STORAGE_BACKEND</code> is using any module from
|
|
17873
|
+
<code>django-storages</code>, if <code>STATICFILES_STORAGE</code> is also using <code>django-storages</code>, the <code>STORAGE_CONFIG</code> will be
|
|
17874
|
+
automatically applied to both file storage types. When using <code>STORAGES</code> instead of <code>STORAGE_CONFIG</code>, this is
|
|
17875
|
+
not automatically the case, permitting the two types to be configured independently, but also potentially
|
|
17876
|
+
requiring duplicate configuration under <code>STORAGES["default"]["OPTIONS"]</code> and
|
|
17877
|
+
<code>STORAGES["staticfiles"]["OPTIONS"]</code> if both types are using the same backend.</p>
|
|
17871
17878
|
</div>
|
|
17872
17879
|
<p>The specific parameters to be used here are specific to each backend.</p>
|
|
17873
17880
|
<p>If <a href="#storage_backend"><code>STORAGE_BACKEND</code></a> is not defined, this setting will be ignored.</p>
|
|
@@ -13139,11 +13139,16 @@
|
|
|
13139
13139
|
<p>To create a Tenant:</p>
|
|
13140
13140
|
<ol>
|
|
13141
13141
|
<li>Click on <strong>Organization</strong> on the left sidebar menu</li>
|
|
13142
|
-
<li>
|
|
13142
|
+
<li>Under <strong>Tenancy</strong> section, select <strong>Tenants</strong><ul>
|
|
13143
|
+
<li>From this page you can view any existing Tenants</li>
|
|
13144
|
+
<li>Click the <code>+ Add Tenant</code> button.</li>
|
|
13145
|
+
</ul>
|
|
13146
|
+
</li>
|
|
13143
13147
|
<li>Populate the <code>Name</code> field</li>
|
|
13144
13148
|
<li>Click the <code>Create</code> button</li>
|
|
13145
13149
|
</ol>
|
|
13146
|
-
<p><img alt="Add tenant" src="../images/getting-started-nautobot-ui/12-add-tenant.png"></
|
|
13150
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/12-add-tenant-light.png#only-light" data-desc-position="bottom"><img alt="Add tenant" class="on-glb" src="../images/getting-started-nautobot-ui/12-add-tenant-light.png#only-light"></a>
|
|
13151
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/12-add-tenant-dark.png#only-dark" data-desc-position="bottom"><img alt="Add tenant" class="on-glb" src="../images/getting-started-nautobot-ui/12-add-tenant-dark.png#only-dark"></a></p>
|
|
13147
13152
|
<h2 id="assigning-a-tenant-to-an-object">Assigning a Tenant to an Object<a class="headerlink" href="#assigning-a-tenant-to-an-object" title="Permanent link">¶</a></h2>
|
|
13148
13153
|
<p>To add a Tenant to an existing Device:</p>
|
|
13149
13154
|
<ol>
|
|
@@ -13158,14 +13163,16 @@
|
|
|
13158
13163
|
</li>
|
|
13159
13164
|
<li>On the specific Device page, click on the <code>Edit</code> button</li>
|
|
13160
13165
|
</ol>
|
|
13161
|
-
<p><img alt="Assign tenant to device 1" src="../images/getting-started-nautobot-ui/13-assign-tenant-to-device.png"></
|
|
13166
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/13-assign-tenant-to-device-light.png#only-light" data-desc-position="bottom"><img alt="Assign tenant to device 1" class="on-glb" src="../images/getting-started-nautobot-ui/13-assign-tenant-to-device-light.png#only-light"></a>
|
|
13167
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/13-assign-tenant-to-device-dark.png#only-dark" data-desc-position="bottom"><img alt="Assign tenant to device 1" class="on-glb" src="../images/getting-started-nautobot-ui/13-assign-tenant-to-device-dark.png#only-dark"></a></p>
|
|
13162
13168
|
<p>Once on the page to edit the Device:</p>
|
|
13163
13169
|
<ol>
|
|
13164
13170
|
<li>Make a selection from the <code>Tenant</code> drop-down menu selector</li>
|
|
13165
13171
|
<li>Click the <code>Update</code> button</li>
|
|
13166
13172
|
</ol>
|
|
13167
13173
|
<p>This will take you back to the main page for the Device.</p>
|
|
13168
|
-
<p><img alt="Assign tenant to device 2" src="../images/getting-started-nautobot-ui/14-assign-tenant-to-device-2.png"></
|
|
13174
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-light.png#only-light" data-desc-position="bottom"><img alt="Assign tenant to device 2" class="on-glb" src="../images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-light.png#only-light"></a>
|
|
13175
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-dark.png#only-dark" data-desc-position="bottom"><img alt="Assign tenant to device 2" class="on-glb" src="../images/getting-started-nautobot-ui/14-assign-tenant-to-device-2-dark.png#only-dark"></a></p>
|
|
13169
13176
|
<p>Notice that the <code>Tenant</code> field is now populated/updated.</p>
|
|
13170
13177
|
|
|
13171
13178
|
|
nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html
CHANGED
|
@@ -13195,7 +13195,11 @@ Refer back to the <a href="creating-devices.html#creating-a-location">Create a L
|
|
|
13195
13195
|
<h3 id="creating-the-vlans">Creating the VLANs<a class="headerlink" href="#creating-the-vlans" title="Permanent link">¶</a></h3>
|
|
13196
13196
|
<ol>
|
|
13197
13197
|
<li>Click on <strong>IPAM</strong> in the left sidebar menu</li>
|
|
13198
|
-
<li>
|
|
13198
|
+
<li>Under the <strong>VLANS</strong> section, select <strong>VLANS</strong>.<ul>
|
|
13199
|
+
<li>From this page, you can view existing VLANs.</li>
|
|
13200
|
+
<li>Click the <code>+ Add VLAN</code> button.</li>
|
|
13201
|
+
</ul>
|
|
13202
|
+
</li>
|
|
13199
13203
|
<li>Populate <code>ID</code> with <code>200</code></li>
|
|
13200
13204
|
<li>Populate <code>Name</code> with <code>vlan 200</code></li>
|
|
13201
13205
|
<li>Select <code>Status</code> as <code>Active</code></li>
|
|
@@ -13205,7 +13209,8 @@ Refer back to the <a href="creating-devices.html#creating-a-location">Create a L
|
|
|
13205
13209
|
<p class="admonition-title">Note</p>
|
|
13206
13210
|
<p>The required parameters to create a new VLAN are bolded in the <code>Add a new VLAN</code> form: <strong>ID</strong>, <strong>Name</strong>, and <strong>Status</strong></p>
|
|
13207
13211
|
</div>
|
|
13208
|
-
<p><img alt="Create VLANs 1" src="../images/getting-started-nautobot-ui/22-create-vlans.png"></
|
|
13212
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/22-create-vlans-light.png#only-light" data-desc-position="bottom"><img alt="Create VLANs 1" class="on-glb" src="../images/getting-started-nautobot-ui/22-create-vlans-light.png#only-light"></a>
|
|
13213
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/22-create-vlans-dark.png#only-dark" data-desc-position="bottom"><img alt="Create VLANs 1" class="on-glb" src="../images/getting-started-nautobot-ui/22-create-vlans-dark.png#only-dark"></a></p>
|
|
13209
13214
|
<p>Now we'll create two instances of VLANs, each with <strong>ID</strong> = <code>100</code> and <strong>Name</strong> = <code>vlan 100</code> and an <code>Active</code> <strong>Status</strong>.
|
|
13210
13215
|
The differentiator will be that one instance will be assigned to the <code>Vancouver 1</code> Site and the other to the <code>Ottawa 1</code> Site.</p>
|
|
13211
13216
|
<p>On the <code>Add a new VLAN</code> form:</p>
|
|
@@ -13224,29 +13229,36 @@ The differentiator will be that one instance will be assigned to the <code>Vanco
|
|
|
13224
13229
|
<li>Select <code>BRE01</code> from the <code>Location</code> selector drop-down</li>
|
|
13225
13230
|
<li>Click on the <code>Create</code> button when complete with the second instance</li>
|
|
13226
13231
|
</ol>
|
|
13227
|
-
<p><img alt="Create VLANs 2" src="../images/getting-started-nautobot-ui/23-create-vlans-2.png"></
|
|
13232
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/23-create-vlans-2-light.png#only-light" data-desc-position="bottom"><img alt="Create VLANs 2" class="on-glb" src="../images/getting-started-nautobot-ui/23-create-vlans-2-light.png#only-light"></a>
|
|
13233
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/23-create-vlans-2-dark.png#only-dark" data-desc-position="bottom"><img alt="Create VLANs 2" class="on-glb" src="../images/getting-started-nautobot-ui/23-create-vlans-2-dark.png#only-dark"></a></p>
|
|
13228
13234
|
<p>Once you've created the three VLANs and then hit the <code>Create</code> button, you will be taken to the <strong>VLANs</strong> main page. On that page,
|
|
13229
13235
|
you'll see the three VLANs and the Location assignment for each one. Each <code>vlan 100</code> instance will have a Location assignment, while
|
|
13230
13236
|
<code>vlan 200</code> will not:</p>
|
|
13231
|
-
<p><img alt="VLAN main page" src="../images/getting-started-nautobot-ui/24-vlan-main-page.png"></
|
|
13237
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/24-vlan-main-page-light.png#only-light" data-desc-position="bottom"><img alt="VLAN main page" class="on-glb" src="../images/getting-started-nautobot-ui/24-vlan-main-page-light.png#only-light"></a>
|
|
13238
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/24-vlan-main-page-dark.png#only-dark" data-desc-position="bottom"><img alt="VLAN main page" class="on-glb" src="../images/getting-started-nautobot-ui/24-vlan-main-page-dark.png#only-dark"></a></p>
|
|
13232
13239
|
<h3 id="assigning-vlans-to-an-interface">Assigning VLANs to an Interface<a class="headerlink" href="#assigning-vlans-to-an-interface" title="Permanent link">¶</a></h3>
|
|
13233
13240
|
<p>To assign a VLAN to an Interface:</p>
|
|
13234
13241
|
<ol>
|
|
13235
|
-
<li>
|
|
13236
|
-
<li>
|
|
13237
|
-
<li>Click on the
|
|
13242
|
+
<li>Click on the <strong>Devices</strong> in the left sidebar menu</li>
|
|
13243
|
+
<li>Under the <strong>Devices</strong> section, select <strong>Devices</strong> to view existing devices.</li>
|
|
13244
|
+
<li>Click on the Devices you wish to add a VLAN to (<code>ang01-edge-01</code>) in this example</li>
|
|
13245
|
+
<li>Click on the <code>Edit</code> button for the <code>xe-0/0/0</code> Interface to go to the <code>Editing interface xe-0/0/0</code> page<ul>
|
|
13238
13246
|
<li>On the <code>Editing interface xe-0/0/0</code> page, set <code>802.1Q</code> Mode to <code>Access</code> (or whatever mode you need) and then click on the VLAN drop-down selector. Notice that there are two choices:<ul>
|
|
13239
13247
|
<li>One choice is the <code>vlan 100</code> instance specifically assigned to the <code>ANG01</code> Location</li>
|
|
13240
13248
|
<li>The other choice is <code>vlan 200</code>, which was not assigned to a Location, and thus has a global scope</li>
|
|
13241
13249
|
</ul>
|
|
13242
13250
|
</li>
|
|
13251
|
+
</ul>
|
|
13252
|
+
</li>
|
|
13243
13253
|
</ol>
|
|
13244
|
-
<p><img alt="Add VLAN to interface 1" src="../images/getting-started-nautobot-ui/25-add-vlan-to-interface.png"></
|
|
13254
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/25-add-vlan-to-interface-light.png#only-light" data-desc-position="bottom"><img alt="Add VLAN to interface 1" class="on-glb" src="../images/getting-started-nautobot-ui/25-add-vlan-to-interface-light.png#only-light"></a>
|
|
13255
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/25-add-vlan-to-interface-dark.png#only-dark" data-desc-position="bottom"><img alt="Add VLAN to interface 1" class="on-glb" src="../images/getting-started-nautobot-ui/25-add-vlan-to-interface-dark.png#only-dark"></a></p>
|
|
13245
13256
|
<div class="admonition note">
|
|
13246
13257
|
<p class="admonition-title">Note</p>
|
|
13247
13258
|
<p>The <code>vlan 100</code> instance that is assigned to the <code>BRE01</code> Location does not show up as an option for the <code>ANG01</code> Location</p>
|
|
13248
13259
|
</div>
|
|
13249
|
-
<p><img alt="Add VLAN to interface 2" src="../images/getting-started-nautobot-ui/26-add-vlan-to-interface-2.png"></
|
|
13260
|
+
<p><a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-light.png#only-light" data-desc-position="bottom"><img alt="Add VLAN to interface 2" class="on-glb" src="../images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-light.png#only-light"></a>
|
|
13261
|
+
<a class="glightbox" data-type="image" data-width="auto" data-height="auto" href="../images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-dark.png#only-dark" data-desc-position="bottom"><img alt="Add VLAN to interface 2" class="on-glb" src="../images/getting-started-nautobot-ui/26-add-vlan-to-interface-2-dark.png#only-dark"></a></p>
|
|
13250
13262
|
|
|
13251
13263
|
|
|
13252
13264
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
nautobot/tenancy/tables.py
CHANGED
|
@@ -35,7 +35,7 @@ class TenantColumn(tables.TemplateColumn):
|
|
|
35
35
|
{% elif record.vrf.tenant %}
|
|
36
36
|
<a href="{{ record.vrf.tenant.get_absolute_url }}" title="{{ record.vrf.tenant.description }}">{{ record.vrf.tenant }}</a>*
|
|
37
37
|
{% else %}
|
|
38
|
-
|
|
38
|
+
<span class="text-secondary">—</span>
|
|
39
39
|
{% endif %}
|
|
40
40
|
"""
|
|
41
41
|
|
nautobot/ui/package-lock.json
CHANGED
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"npm-run-all2": "^8.0.4",
|
|
42
42
|
"postcss": "^8.5.6",
|
|
43
43
|
"postcss-loader": "^8.2.0",
|
|
44
|
-
"prettier": "^3.
|
|
45
|
-
"sass": "^1.
|
|
44
|
+
"prettier": "^3.7.4",
|
|
45
|
+
"sass": "^1.97.1",
|
|
46
46
|
"sass-loader": "^16.0.6",
|
|
47
|
-
"webpack": "^5.
|
|
47
|
+
"webpack": "^5.104.1",
|
|
48
48
|
"webpack-cli": "^6.0.1"
|
|
49
49
|
}
|
|
50
50
|
},
|
|
@@ -98,9 +98,9 @@
|
|
|
98
98
|
}
|
|
99
99
|
},
|
|
100
100
|
"node_modules/@codemirror/state": {
|
|
101
|
-
"version": "6.5.
|
|
102
|
-
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.
|
|
103
|
-
"integrity": "sha512-
|
|
101
|
+
"version": "6.5.3",
|
|
102
|
+
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.3.tgz",
|
|
103
|
+
"integrity": "sha512-MerMzJzlXogk2fxWFU1nKp36bY5orBG59HnPiz0G9nLRebWa0zXuv2siH6PLIHBvv5TH8CkQRqjBs0MlxCZu+A==",
|
|
104
104
|
"license": "MIT",
|
|
105
105
|
"peer": true,
|
|
106
106
|
"dependencies": {
|
|
@@ -108,9 +108,9 @@
|
|
|
108
108
|
}
|
|
109
109
|
},
|
|
110
110
|
"node_modules/@codemirror/view": {
|
|
111
|
-
"version": "6.39.
|
|
112
|
-
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.
|
|
113
|
-
"integrity": "sha512-
|
|
111
|
+
"version": "6.39.8",
|
|
112
|
+
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.8.tgz",
|
|
113
|
+
"integrity": "sha512-1rASYd9Z/mE3tkbC9wInRlCNyCkSn+nLsiQKZhEDUUJiUfs/5FHDpCUDaQpoTIaNGeDc6/bhaEAyLmeEucEFPw==",
|
|
114
114
|
"license": "MIT",
|
|
115
115
|
"peer": true,
|
|
116
116
|
"dependencies": {
|
|
@@ -131,9 +131,9 @@
|
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
133
|
"node_modules/@eslint-community/eslint-utils": {
|
|
134
|
-
"version": "4.9.
|
|
135
|
-
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.
|
|
136
|
-
"integrity": "sha512-
|
|
134
|
+
"version": "4.9.1",
|
|
135
|
+
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
|
|
136
|
+
"integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==",
|
|
137
137
|
"dev": true,
|
|
138
138
|
"license": "MIT",
|
|
139
139
|
"dependencies": {
|
|
@@ -481,9 +481,9 @@
|
|
|
481
481
|
}
|
|
482
482
|
},
|
|
483
483
|
"node_modules/@lezer/common": {
|
|
484
|
-
"version": "1.
|
|
485
|
-
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.
|
|
486
|
-
"integrity": "sha512-
|
|
484
|
+
"version": "1.5.0",
|
|
485
|
+
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.0.tgz",
|
|
486
|
+
"integrity": "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==",
|
|
487
487
|
"license": "MIT",
|
|
488
488
|
"peer": true
|
|
489
489
|
},
|
|
@@ -1146,9 +1146,9 @@
|
|
|
1146
1146
|
"license": "MIT"
|
|
1147
1147
|
},
|
|
1148
1148
|
"node_modules/@types/node": {
|
|
1149
|
-
"version": "25.0.
|
|
1150
|
-
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.
|
|
1151
|
-
"integrity": "sha512-
|
|
1149
|
+
"version": "25.0.3",
|
|
1150
|
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
|
|
1151
|
+
"integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==",
|
|
1152
1152
|
"devOptional": true,
|
|
1153
1153
|
"license": "MIT",
|
|
1154
1154
|
"dependencies": {
|
|
@@ -1702,9 +1702,9 @@
|
|
|
1702
1702
|
"license": "MIT"
|
|
1703
1703
|
},
|
|
1704
1704
|
"node_modules/baseline-browser-mapping": {
|
|
1705
|
-
"version": "2.9.
|
|
1706
|
-
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.
|
|
1707
|
-
"integrity": "sha512-
|
|
1705
|
+
"version": "2.9.11",
|
|
1706
|
+
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz",
|
|
1707
|
+
"integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==",
|
|
1708
1708
|
"dev": true,
|
|
1709
1709
|
"license": "Apache-2.0",
|
|
1710
1710
|
"bin": {
|
|
@@ -1857,9 +1857,9 @@
|
|
|
1857
1857
|
}
|
|
1858
1858
|
},
|
|
1859
1859
|
"node_modules/caniuse-lite": {
|
|
1860
|
-
"version": "1.0.
|
|
1861
|
-
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.
|
|
1862
|
-
"integrity": "sha512-
|
|
1860
|
+
"version": "1.0.30001762",
|
|
1861
|
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz",
|
|
1862
|
+
"integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==",
|
|
1863
1863
|
"dev": true,
|
|
1864
1864
|
"funding": [
|
|
1865
1865
|
{
|
|
@@ -2794,9 +2794,9 @@
|
|
|
2794
2794
|
}
|
|
2795
2795
|
},
|
|
2796
2796
|
"node_modules/esquery": {
|
|
2797
|
-
"version": "1.
|
|
2798
|
-
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.
|
|
2799
|
-
"integrity": "sha512-
|
|
2797
|
+
"version": "1.7.0",
|
|
2798
|
+
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
|
|
2799
|
+
"integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
|
|
2800
2800
|
"dev": true,
|
|
2801
2801
|
"license": "BSD-3-Clause",
|
|
2802
2802
|
"dependencies": {
|
|
@@ -5432,9 +5432,9 @@
|
|
|
5432
5432
|
}
|
|
5433
5433
|
},
|
|
5434
5434
|
"node_modules/sass": {
|
|
5435
|
-
"version": "1.97.
|
|
5436
|
-
"resolved": "https://registry.npmjs.org/sass/-/sass-1.97.
|
|
5437
|
-
"integrity": "sha512-
|
|
5435
|
+
"version": "1.97.1",
|
|
5436
|
+
"resolved": "https://registry.npmjs.org/sass/-/sass-1.97.1.tgz",
|
|
5437
|
+
"integrity": "sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==",
|
|
5438
5438
|
"dev": true,
|
|
5439
5439
|
"license": "MIT",
|
|
5440
5440
|
"dependencies": {
|
|
@@ -6326,9 +6326,9 @@
|
|
|
6326
6326
|
"peer": true
|
|
6327
6327
|
},
|
|
6328
6328
|
"node_modules/watchpack": {
|
|
6329
|
-
"version": "2.
|
|
6330
|
-
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.
|
|
6331
|
-
"integrity": "sha512-
|
|
6329
|
+
"version": "2.5.0",
|
|
6330
|
+
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.0.tgz",
|
|
6331
|
+
"integrity": "sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==",
|
|
6332
6332
|
"dev": true,
|
|
6333
6333
|
"license": "MIT",
|
|
6334
6334
|
"dependencies": {
|
|
@@ -6340,9 +6340,9 @@
|
|
|
6340
6340
|
}
|
|
6341
6341
|
},
|
|
6342
6342
|
"node_modules/webpack": {
|
|
6343
|
-
"version": "5.104.
|
|
6344
|
-
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.
|
|
6345
|
-
"integrity": "sha512-
|
|
6343
|
+
"version": "5.104.1",
|
|
6344
|
+
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz",
|
|
6345
|
+
"integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
|
|
6346
6346
|
"dev": true,
|
|
6347
6347
|
"license": "MIT",
|
|
6348
6348
|
"dependencies": {
|
nautobot/ui/package.json
CHANGED
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"npm-run-all2": "^8.0.4",
|
|
48
48
|
"postcss": "^8.5.6",
|
|
49
49
|
"postcss-loader": "^8.2.0",
|
|
50
|
-
"prettier": "^3.
|
|
51
|
-
"sass": "^1.
|
|
50
|
+
"prettier": "^3.7.4",
|
|
51
|
+
"sass": "^1.97.1",
|
|
52
52
|
"sass-loader": "^16.0.6",
|
|
53
|
-
"webpack": "^5.
|
|
53
|
+
"webpack": "^5.104.1",
|
|
54
54
|
"webpack-cli": "^6.0.1"
|
|
55
55
|
},
|
|
56
56
|
"devEngines": {
|
nautobot/users/models.py
CHANGED
|
@@ -14,6 +14,7 @@ from nautobot.core.constants import CHARFIELD_MAX_LENGTH
|
|
|
14
14
|
from nautobot.core.models import BaseManager, BaseModel, CompositeKeyQuerySetMixin
|
|
15
15
|
from nautobot.core.models.fields import JSONArrayField
|
|
16
16
|
from nautobot.core.utils.data import flatten_dict
|
|
17
|
+
from nautobot.core.utils.permissions import resolve_permission
|
|
17
18
|
from nautobot.extras.models.change_logging import ChangeLoggedModel
|
|
18
19
|
|
|
19
20
|
__all__ = (
|
|
@@ -73,6 +74,38 @@ class User(BaseModel, AbstractUser):
|
|
|
73
74
|
db_table = "auth_user"
|
|
74
75
|
ordering = ["username"]
|
|
75
76
|
|
|
77
|
+
def has_perm(self, perm, obj=None):
|
|
78
|
+
"""
|
|
79
|
+
Override Django's default permission check to enforce read-only access
|
|
80
|
+
during Nautobot Version Control time-travel mode.
|
|
81
|
+
|
|
82
|
+
If the ``nautobot_version_control`` plugin is installed and time-travel
|
|
83
|
+
mode is active, all non-view permissions (e.g. add, change, delete) are
|
|
84
|
+
explicitly denied, regardless of the user's role or superuser status.
|
|
85
|
+
|
|
86
|
+
When the plugin is not installed or time-travel mode is inactive, this
|
|
87
|
+
method delegates entirely to Django's standard permission handling via
|
|
88
|
+
the parent implementation.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
perm (str): Permission string in the form "app_label.codename".
|
|
92
|
+
obj (Optional[Model]): Optional object-level permission target.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
bool: False when time-travel mode is active and the requested
|
|
96
|
+
permission is not a view permission; otherwise, the boolean result
|
|
97
|
+
returned by Django's default permission resolution logic.
|
|
98
|
+
"""
|
|
99
|
+
if "nautobot_version_control" in settings.PLUGINS:
|
|
100
|
+
from nautobot_version_control.utils import get_time_travel_datetime # pylint: disable=import-error
|
|
101
|
+
|
|
102
|
+
if get_time_travel_datetime() is not None:
|
|
103
|
+
_app_label, action, _model_name = resolve_permission(perm)
|
|
104
|
+
if action != "view":
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
return super().has_perm(perm, obj)
|
|
108
|
+
|
|
76
109
|
def get_config(self, path, default=None):
|
|
77
110
|
"""
|
|
78
111
|
Retrieve a configuration parameter specified by its dotted path. Example:
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
from datetime import date, timedelta
|
|
2
|
+
from unittest import mock
|
|
3
|
+
|
|
1
4
|
from django.contrib.auth import get_user_model
|
|
5
|
+
from django.test.utils import override_settings
|
|
2
6
|
|
|
3
7
|
from nautobot.core.testing.models import ModelTestCases
|
|
4
8
|
from nautobot.users.models import ObjectPermission, Token
|
|
@@ -121,3 +125,82 @@ class UserConfigTest(ModelTestCases.BaseModelTestCase):
|
|
|
121
125
|
|
|
122
126
|
# Clear a non-existing value; should fail silently
|
|
123
127
|
self.user.clear_config("invalid")
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@override_settings(PLUGINS=["nautobot_version_control"])
|
|
131
|
+
class UserHasPermTest(ModelTestCases.BaseModelTestCase):
|
|
132
|
+
model = User
|
|
133
|
+
|
|
134
|
+
def setUp(self):
|
|
135
|
+
self.user = User.objects.create_user(username="testuser")
|
|
136
|
+
self.add_permissions("dcim.add_device", "dcim.view_device")
|
|
137
|
+
|
|
138
|
+
@mock.patch("django.contrib.auth.models.AbstractUser.has_perm")
|
|
139
|
+
def test_time_travel_blocks_non_view_permission(self, mock_super_has_perm):
|
|
140
|
+
with mock.patch.dict(
|
|
141
|
+
"sys.modules",
|
|
142
|
+
{
|
|
143
|
+
"nautobot_version_control.utils": mock.MagicMock(),
|
|
144
|
+
},
|
|
145
|
+
):
|
|
146
|
+
from nautobot_version_control.utils import get_time_travel_datetime # pylint: disable=import-error
|
|
147
|
+
|
|
148
|
+
get_time_travel_datetime.return_value = (date.today() + timedelta(days=1)).isoformat()
|
|
149
|
+
|
|
150
|
+
perm = "dcim.add_device"
|
|
151
|
+
result = self.user.has_perm(perm)
|
|
152
|
+
self.assertFalse(result)
|
|
153
|
+
mock_super_has_perm.assert_not_called()
|
|
154
|
+
|
|
155
|
+
@mock.patch("django.contrib.auth.models.AbstractUser.has_perm")
|
|
156
|
+
def test_time_travel_blocks_non_view_permission_for_superuser(self, mock_super_has_perm):
|
|
157
|
+
with mock.patch.dict(
|
|
158
|
+
"sys.modules",
|
|
159
|
+
{
|
|
160
|
+
"nautobot_version_control.utils": mock.MagicMock(),
|
|
161
|
+
},
|
|
162
|
+
):
|
|
163
|
+
from nautobot_version_control.utils import get_time_travel_datetime # pylint: disable=import-error
|
|
164
|
+
|
|
165
|
+
get_time_travel_datetime.return_value = date.today() + timedelta(days=1)
|
|
166
|
+
perm = "dcim.add_device"
|
|
167
|
+
self.user.is_superuser = True
|
|
168
|
+
self.user.save()
|
|
169
|
+
|
|
170
|
+
self.assertTrue(self.user.is_superuser)
|
|
171
|
+
|
|
172
|
+
result = self.user.has_perm(perm)
|
|
173
|
+
self.assertFalse(result)
|
|
174
|
+
mock_super_has_perm.assert_not_called()
|
|
175
|
+
|
|
176
|
+
@mock.patch("django.contrib.auth.models.AbstractUser.has_perm")
|
|
177
|
+
def test_time_travel_allows_view_permission(self, mock_super_has_perm):
|
|
178
|
+
with mock.patch.dict(
|
|
179
|
+
"sys.modules",
|
|
180
|
+
{
|
|
181
|
+
"nautobot_version_control.utils": mock.MagicMock(),
|
|
182
|
+
},
|
|
183
|
+
):
|
|
184
|
+
from nautobot_version_control.utils import get_time_travel_datetime # pylint: disable=import-error
|
|
185
|
+
|
|
186
|
+
get_time_travel_datetime.return_value = date.today() + timedelta(days=1)
|
|
187
|
+
perm = "dcim.view_device"
|
|
188
|
+
result = self.user.has_perm(perm)
|
|
189
|
+
self.assertTrue(result)
|
|
190
|
+
mock_super_has_perm.assert_called_once_with(perm, None)
|
|
191
|
+
|
|
192
|
+
@mock.patch("django.contrib.auth.models.AbstractUser.has_perm")
|
|
193
|
+
def test_no_time_travel_does_not_block_permissions(self, mock_super_has_perm):
|
|
194
|
+
with mock.patch.dict(
|
|
195
|
+
"sys.modules",
|
|
196
|
+
{
|
|
197
|
+
"nautobot_version_control.utils": mock.MagicMock(),
|
|
198
|
+
},
|
|
199
|
+
):
|
|
200
|
+
from nautobot_version_control.utils import get_time_travel_datetime # pylint: disable=import-error
|
|
201
|
+
|
|
202
|
+
get_time_travel_datetime.return_value = None
|
|
203
|
+
perm = "dcim.add_device"
|
|
204
|
+
result = self.user.has_perm(perm)
|
|
205
|
+
self.assertTrue(result)
|
|
206
|
+
mock_super_has_perm.assert_called_once_with(perm, None)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: nautobot
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.4
|
|
4
4
|
Summary: Source of truth and network automation platform.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: Nautobot
|
|
@@ -22,12 +22,12 @@ Provides-Extra: napalm
|
|
|
22
22
|
Provides-Extra: remote-storage
|
|
23
23
|
Provides-Extra: sso
|
|
24
24
|
Requires-Dist: Django (>=4.2.27,<4.3.0)
|
|
25
|
-
Requires-Dist: GitPython (>=3.1.
|
|
25
|
+
Requires-Dist: GitPython (>=3.1.46,<3.2.0)
|
|
26
26
|
Requires-Dist: Jinja2 (>=3.1.6,<3.2.0)
|
|
27
27
|
Requires-Dist: Markdown (>=3.8.2,<3.9.0)
|
|
28
28
|
Requires-Dist: Pillow (>=12.0.0,<12.1.0)
|
|
29
29
|
Requires-Dist: PyYAML (>=6.0.3,<6.1.0)
|
|
30
|
-
Requires-Dist: celery (>=5.6.
|
|
30
|
+
Requires-Dist: celery (>=5.6.1,<5.7.0)
|
|
31
31
|
Requires-Dist: cryptography (>=46.0.3,<46.1.0)
|
|
32
32
|
Requires-Dist: django-ajax-tables (>=1.1.1,<1.2.0)
|
|
33
33
|
Requires-Dist: django-auth-ldap (>=5.2.0,<5.3.0) ; extra == "all" or extra == "ldap"
|
|
@@ -38,7 +38,7 @@ Requires-Dist: django-cors-headers (>=4.9.0,<4.10.0)
|
|
|
38
38
|
Requires-Dist: django-db-file-storage (>=0.5.6.1,<0.6.0.0)
|
|
39
39
|
Requires-Dist: django-extensions (>=4.1,<4.2)
|
|
40
40
|
Requires-Dist: django-filter (>=25.1,<25.2)
|
|
41
|
-
Requires-Dist: django-health-check (>=3.20.
|
|
41
|
+
Requires-Dist: django-health-check (>=3.20.8,<3.21.0)
|
|
42
42
|
Requires-Dist: django-jinja (>=2.11.0,<2.12.0)
|
|
43
43
|
Requires-Dist: django-prometheus (>=2.4.1,<2.5.0)
|
|
44
44
|
Requires-Dist: django-redis (>=6.0.0,<6.1.0)
|