From 2fcdc90d3f8addfa05e873b2758560c3b92b9792 Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Fri, 24 Jan 2020 00:15:32 +0100 Subject: [PATCH 01/11] Automatically check for new versions --- docs/configuration/optional-settings.md | 16 +++++++++++++++ netbox/netbox/configuration.example.py | 8 ++++++++ netbox/netbox/settings.py | 10 +++++++++ netbox/templates/_base.html | 11 +++++++++- netbox/utilities/context_processors.py | 23 +++++++++++++++++++++ netbox/utilities/versions.py | 27 +++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 netbox/utilities/versions.py diff --git a/docs/configuration/optional-settings.md b/docs/configuration/optional-settings.md index cbe01728c..36687343a 100644 --- a/docs/configuration/optional-settings.md +++ b/docs/configuration/optional-settings.md @@ -157,6 +157,22 @@ Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce uni --- +## GITHUB_REPOSITORY + +Default: 'netbox-community/netbox' + +The tags of this repository are checked to detect new releases, which are shown in the footer of the web interface. You can change this to your own fork of the NetBox repository, or set it to `None` to disable the check. + +--- + +## GITHUB_VERSION_TIMEOUT + +Default: 8 * 3600 + +The number of seconds to retain the latest version that is fetched from the GitHub API before automatically invalidating it and fetching it from the API again. Set to 0 to disable the version check. + +--- + ## LOGGING By default, all messages of INFO severity or higher will be logged to the console. Additionally, if `DEBUG` is False and email access has been configured, ERROR and CRITICAL messages will be emailed to the users defined in `ADMINS`. diff --git a/netbox/netbox/configuration.example.py b/netbox/netbox/configuration.example.py index 7002def9b..63521789a 100644 --- a/netbox/netbox/configuration.example.py +++ b/netbox/netbox/configuration.example.py @@ -124,6 +124,14 @@ EXEMPT_VIEW_PERMISSIONS = [ # 'ipam.prefix', ] +# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the +# version check. +GITHUB_REPOSITORY = 'netbox-community/netbox' + +# This determines how often the GitHub API is called to check the latest release of NetBox. Set to 0 to disable the +# version check. +GITHUB_VERSION_TIMEOUT = 8 * 3600 + # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: # https://docs.djangoproject.com/en/stable/topics/logging/ LOGGING = {} diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 89958bc13..1e598f85d 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -1,6 +1,7 @@ import logging import os import platform +import re import socket import warnings @@ -78,6 +79,8 @@ DEVELOPER = getattr(configuration, 'DEVELOPER', False) EMAIL = getattr(configuration, 'EMAIL', {}) ENFORCE_GLOBAL_UNIQUE = getattr(configuration, 'ENFORCE_GLOBAL_UNIQUE', False) EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', []) +GITHUB_REPOSITORY = getattr(configuration, 'GITHUB_REPOSITORY', 'netbox-community/netbox') +GITHUB_VERSION_TIMEOUT = getattr(configuration, 'GITHUB_VERSION_TIMEOUT', 8 * 3600) LOGGING = getattr(configuration, 'LOGGING', {}) LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', False) LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None) @@ -292,6 +295,7 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'utilities.context_processors.settings', + 'utilities.context_processors.latest_version', ], }, }, @@ -302,6 +306,12 @@ AUTHENTICATION_BACKENDS = [ 'utilities.auth_backends.ViewExemptModelBackend', ] +# GitHub repository for version check +if GITHUB_REPOSITORY and not re.fullmatch(r'[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+', GITHUB_REPOSITORY): + raise ImproperlyConfigured( + "GITHUB_REPOSITORY must contain the name of a GitHub repository in the form '/'" + ) + # Internationalization LANGUAGE_CODE = 'en-us' USE_I18N = True diff --git a/netbox/templates/_base.html b/netbox/templates/_base.html index 1b7a9da80..cfc2a9cc8 100644 --- a/netbox/templates/_base.html +++ b/netbox/templates/_base.html @@ -50,7 +50,16 @@
-

{{ settings.HOSTNAME }} (v{{ settings.VERSION }})

+

+ {{ settings.HOSTNAME }} (v{{ settings.VERSION }}) + {% if latest_version %} + {% if latest_version_url %}{% endif %} + + New version: {{ latest_version }} + + {% if latest_version_url %}{% endif %} + {% endif %} +

{% now 'Y-m-d H:i:s T' %}

diff --git a/netbox/utilities/context_processors.py b/netbox/utilities/context_processors.py index 06c5c8784..b12a127fa 100644 --- a/netbox/utilities/context_processors.py +++ b/netbox/utilities/context_processors.py @@ -1,4 +1,7 @@ from django.conf import settings as django_settings +from packaging import version + +from utilities.versions import get_latest_version def settings(request): @@ -8,3 +11,23 @@ def settings(request): return { 'settings': django_settings, } + + +def latest_version(request): + """ + Get the latest version from the GitHub repository + """ + github_latest_version, github_url = get_latest_version() + + latest_version_str = None + latest_version_url = None + if isinstance(github_latest_version, version.Version): + current_version = version.parse(django_settings.VERSION) + if github_latest_version > current_version: + latest_version_str = str(github_latest_version) + latest_version_url = github_url + + return { + 'latest_version': latest_version_str, + 'latest_version_url': latest_version_url + } diff --git a/netbox/utilities/versions.py b/netbox/utilities/versions.py new file mode 100644 index 000000000..bebe26fba --- /dev/null +++ b/netbox/utilities/versions.py @@ -0,0 +1,27 @@ +import requests +from cacheops import cached +from django.conf import settings +from packaging import version + +if settings.GITHUB_VERSION_TIMEOUT and settings.GITHUB_REPOSITORY: + @cached(timeout=settings.GITHUB_VERSION_TIMEOUT) + def get_latest_version(): + url = 'https://api.github.com/repos/{}/releases'.format(settings.GITHUB_REPOSITORY) + headers = { + 'Accept': 'application/vnd.github.v3+json', + } + try: + response = requests.get(url, headers=headers) + versions = [(version.parse(release['tag_name']), release.get('html_url')) + for release in response.json() + if 'tag_name' in release] + if versions: + return max(versions) + except: + pass + + return 'unknown', None + +else: + def get_latest_version(): + return None From 405d93c6f272047c568f984941e09cbfb34fe1f3 Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Fri, 24 Jan 2020 10:11:32 +0100 Subject: [PATCH 02/11] Update versions.py --- netbox/utilities/versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/utilities/versions.py b/netbox/utilities/versions.py index bebe26fba..40d5d90af 100644 --- a/netbox/utilities/versions.py +++ b/netbox/utilities/versions.py @@ -17,7 +17,7 @@ if settings.GITHUB_VERSION_TIMEOUT and settings.GITHUB_REPOSITORY: if 'tag_name' in release] if versions: return max(versions) - except: + except Exception: pass return 'unknown', None From 9d66ac4a6a8cb6e65ba21549c50a71bc66881ae4 Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Fri, 24 Jan 2020 18:06:10 +0100 Subject: [PATCH 03/11] Refactor the code to be more readable --- netbox/utilities/context_processors.py | 10 +++--- netbox/utilities/versions.py | 48 +++++++++++++++----------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/netbox/utilities/context_processors.py b/netbox/utilities/context_processors.py index b12a127fa..5dadf55da 100644 --- a/netbox/utilities/context_processors.py +++ b/netbox/utilities/context_processors.py @@ -1,7 +1,7 @@ from django.conf import settings as django_settings from packaging import version -from utilities.versions import get_latest_version +from utilities.versions import get_latest_release def settings(request): @@ -17,14 +17,14 @@ def latest_version(request): """ Get the latest version from the GitHub repository """ - github_latest_version, github_url = get_latest_version() + latest_release, github_url = get_latest_release() latest_version_str = None latest_version_url = None - if isinstance(github_latest_version, version.Version): + if isinstance(latest_release, version.Version): current_version = version.parse(django_settings.VERSION) - if github_latest_version > current_version: - latest_version_str = str(github_latest_version) + if latest_release > current_version: + latest_version_str = str(latest_release) latest_version_url = github_url return { diff --git a/netbox/utilities/versions.py b/netbox/utilities/versions.py index 40d5d90af..72341c8f7 100644 --- a/netbox/utilities/versions.py +++ b/netbox/utilities/versions.py @@ -3,25 +3,33 @@ from cacheops import cached from django.conf import settings from packaging import version -if settings.GITHUB_VERSION_TIMEOUT and settings.GITHUB_REPOSITORY: - @cached(timeout=settings.GITHUB_VERSION_TIMEOUT) - def get_latest_version(): - url = 'https://api.github.com/repos/{}/releases'.format(settings.GITHUB_REPOSITORY) - headers = { - 'Accept': 'application/vnd.github.v3+json', - } - try: - response = requests.get(url, headers=headers) - versions = [(version.parse(release['tag_name']), release.get('html_url')) - for release in response.json() - if 'tag_name' in release] - if versions: - return max(versions) - except Exception: - pass - return 'unknown', None +@cached(timeout=settings.GITHUB_VERSION_TIMEOUT if settings.GITHUB_VERSION_TIMEOUT > 0 else 1) +def get_releases(pre_releases=False): + url = 'https://api.github.com/repos/{}/releases'.format(settings.GITHUB_REPOSITORY) + headers = { + 'Accept': 'application/vnd.github.v3+json', + } + try: + response = requests.get(url, headers=headers) + releases = [(version.parse(release['tag_name']), release.get('html_url')) + for release in response.json() + if 'tag_name' in release] + except Exception: + releases = [] -else: - def get_latest_version(): - return None + if not pre_releases: + releases = [(release, url) + for release, url in releases + if not release.is_devrelease and not release.is_prerelease] + + return releases + + +def get_latest_release(pre_releases=False): + if settings.GITHUB_VERSION_TIMEOUT > 0 and settings.GITHUB_REPOSITORY: + releases = get_releases(pre_releases) + if releases: + return max(releases) + + return 'unknown', None From 008fc5623e692f57b282a9ee49a3fd2d8c74347e Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Sun, 26 Jan 2020 16:50:15 +0100 Subject: [PATCH 04/11] Full URL for API, more consistent naming, only enabled for staff and better configuration validation --- docs/configuration/optional-settings.md | 12 +++---- netbox/netbox/configuration.example.py | 7 ++-- netbox/netbox/settings.py | 33 +++++++++++++++---- netbox/netbox/views.py | 21 ++++++++++-- netbox/templates/_base.html | 11 +------ netbox/templates/home.html | 12 +++++++ netbox/utilities/context_processors.py | 23 ------------- netbox/utilities/{versions.py => releases.py} | 6 ++-- 8 files changed, 70 insertions(+), 55 deletions(-) rename netbox/utilities/{versions.py => releases.py} (77%) diff --git a/docs/configuration/optional-settings.md b/docs/configuration/optional-settings.md index 36687343a..5a3121960 100644 --- a/docs/configuration/optional-settings.md +++ b/docs/configuration/optional-settings.md @@ -157,19 +157,19 @@ Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce uni --- -## GITHUB_REPOSITORY +## GITHUB_REPOSITORY_API -Default: 'netbox-community/netbox' +Default: 'https://api.github.com/repos/netbox-community/netbox' -The tags of this repository are checked to detect new releases, which are shown in the footer of the web interface. You can change this to your own fork of the NetBox repository, or set it to `None` to disable the check. +The releases of this repository are checked to detect new releases, which are shown on the home page of the web interface. You can change this to your own fork of the NetBox repository, or set it to `None` to disable the check. --- -## GITHUB_VERSION_TIMEOUT +## GITHUB_CACHE_TIMEOUT -Default: 8 * 3600 +Default: 24 * 3600 -The number of seconds to retain the latest version that is fetched from the GitHub API before automatically invalidating it and fetching it from the API again. Set to 0 to disable the version check. +The number of seconds to retain the latest version that is fetched from the GitHub API before automatically invalidating it and fetching it from the API again. This must be set to at least one hour (3600 seconds). --- diff --git a/netbox/netbox/configuration.example.py b/netbox/netbox/configuration.example.py index 63521789a..b24db0f03 100644 --- a/netbox/netbox/configuration.example.py +++ b/netbox/netbox/configuration.example.py @@ -126,11 +126,10 @@ EXEMPT_VIEW_PERMISSIONS = [ # This repository is used to check whether there is a new release of NetBox available. Set to None to disable the # version check. -GITHUB_REPOSITORY = 'netbox-community/netbox' +GITHUB_REPOSITORY_API = 'https://api.github.com/repos/netbox-community/netbox' -# This determines how often the GitHub API is called to check the latest release of NetBox. Set to 0 to disable the -# version check. -GITHUB_VERSION_TIMEOUT = 8 * 3600 +# This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. +GITHUB_CACHE_TIMEOUT = 24 * 3600 # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: # https://docs.djangoproject.com/en/stable/topics/logging/ diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 1e598f85d..43b5428f9 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -4,6 +4,7 @@ import platform import re import socket import warnings +from urllib.parse import urlsplit from django.contrib.messages import constants as messages from django.core.exceptions import ImproperlyConfigured @@ -79,8 +80,9 @@ DEVELOPER = getattr(configuration, 'DEVELOPER', False) EMAIL = getattr(configuration, 'EMAIL', {}) ENFORCE_GLOBAL_UNIQUE = getattr(configuration, 'ENFORCE_GLOBAL_UNIQUE', False) EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', []) -GITHUB_REPOSITORY = getattr(configuration, 'GITHUB_REPOSITORY', 'netbox-community/netbox') -GITHUB_VERSION_TIMEOUT = getattr(configuration, 'GITHUB_VERSION_TIMEOUT', 8 * 3600) +GITHUB_REPOSITORY_API = getattr(configuration, 'GITHUB_REPOSITORY_API', + 'https://api.github.com/repos/netbox-community/netbox') +GITHUB_CACHE_TIMEOUT = getattr(configuration, 'GITHUB_CACHE_TIMEOUT', 24 * 3600) LOGGING = getattr(configuration, 'LOGGING', {}) LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', False) LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None) @@ -295,7 +297,6 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'utilities.context_processors.settings', - 'utilities.context_processors.latest_version', ], }, }, @@ -307,10 +308,28 @@ AUTHENTICATION_BACKENDS = [ ] # GitHub repository for version check -if GITHUB_REPOSITORY and not re.fullmatch(r'[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+', GITHUB_REPOSITORY): - raise ImproperlyConfigured( - "GITHUB_REPOSITORY must contain the name of a GitHub repository in the form '/'" - ) +if GITHUB_REPOSITORY_API: + GITHUB_REPOSITORY_API = GITHUB_REPOSITORY_API.rstrip('/') + try: + scheme, netloc, path, query, fragment = urlsplit(GITHUB_REPOSITORY_API) + except ValueError: + raise ImproperlyConfigured("GITHUB_REPOSITORY_API must be a valid URL") + + if scheme not in ('http', 'https'): + raise ImproperlyConfigured("GITHUB_REPOSITORY_API must be a valid http:// or https:// URL") + + if not re.fullmatch(r'/repos/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+', path): + raise ImproperlyConfigured( + "GITHUB_REPOSITORY must contain the base URL of the GitHub API in a form like " + "'https://api.github.com/repos//'" + ) + + if query or fragment: + raise ImproperlyConfigured("GITHUB_REPOSITORY_API may not contain a query or fragment") + +# Enforce a cache timeout of at least an hour to protect GitHub +if GITHUB_CACHE_TIMEOUT < 3600: + raise ImproperlyConfigured("GITHUB_CACHE_TIMEOUT has to be at least 3600 seconds (1 hour)") # Internationalization LANGUAGE_CODE = 'en-us' diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index 05bcea90d..9afa9c73a 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -1,8 +1,10 @@ from collections import OrderedDict -from django.db.models import Count, F +from django.conf import settings +from django.db.models import Count, F, OuterRef, Subquery from django.shortcuts import render from django.views.generic import View +from packaging import version from rest_framework.response import Response from rest_framework.reverse import reverse from rest_framework.views import APIView @@ -31,6 +33,7 @@ from secrets.tables import SecretTable from tenancy.filters import TenantFilterSet from tenancy.models import Tenant from tenancy.tables import TenantTable +from utilities.releases import get_latest_release from virtualization.filters import ClusterFilterSet, VirtualMachineFilterSet from virtualization.models import Cluster, VirtualMachine from virtualization.tables import ClusterTable, VirtualMachineDetailTable @@ -240,11 +243,25 @@ class HomeView(View): } + new_release = None + new_release_url = None + + if request.user.is_staff: + # Only check for new releases if the current user might be able to do anything about it + latest_release, github_url = get_latest_release() + if isinstance(latest_release, version.Version): + current_version = version.parse(settings.VERSION) + if latest_release > current_version: + new_release = str(latest_release) + new_release_url = github_url + return render(request, self.template_name, { 'search_form': SearchForm(), 'stats': stats, 'report_results': ReportResult.objects.order_by('-created')[:10], - 'changelog': ObjectChange.objects.prefetch_related('user', 'changed_object_type')[:15] + 'changelog': ObjectChange.objects.prefetch_related('user', 'changed_object_type')[:15], + 'new_release': new_release, + 'new_release_url': new_release_url, }) diff --git a/netbox/templates/_base.html b/netbox/templates/_base.html index cfc2a9cc8..1b7a9da80 100644 --- a/netbox/templates/_base.html +++ b/netbox/templates/_base.html @@ -50,16 +50,7 @@
-

- {{ settings.HOSTNAME }} (v{{ settings.VERSION }}) - {% if latest_version %} - {% if latest_version_url %}{% endif %} - - New version: {{ latest_version }} - - {% if latest_version_url %}{% endif %} - {% endif %} -

+

{{ settings.HOSTNAME }} (v{{ settings.VERSION }})

{% now 'Y-m-d H:i:s T' %}

diff --git a/netbox/templates/home.html b/netbox/templates/home.html index 6977bba4c..ed6ef06d6 100644 --- a/netbox/templates/home.html +++ b/netbox/templates/home.html @@ -1,6 +1,18 @@ {% extends '_base.html' %} {% load helpers %} +{% block header %} + {% if new_release %} + + {% endif %} +{% endblock %} + + {% block content %} {% include 'search_form.html' %}
diff --git a/netbox/utilities/context_processors.py b/netbox/utilities/context_processors.py index 5dadf55da..06c5c8784 100644 --- a/netbox/utilities/context_processors.py +++ b/netbox/utilities/context_processors.py @@ -1,7 +1,4 @@ from django.conf import settings as django_settings -from packaging import version - -from utilities.versions import get_latest_release def settings(request): @@ -11,23 +8,3 @@ def settings(request): return { 'settings': django_settings, } - - -def latest_version(request): - """ - Get the latest version from the GitHub repository - """ - latest_release, github_url = get_latest_release() - - latest_version_str = None - latest_version_url = None - if isinstance(latest_release, version.Version): - current_version = version.parse(django_settings.VERSION) - if latest_release > current_version: - latest_version_str = str(latest_release) - latest_version_url = github_url - - return { - 'latest_version': latest_version_str, - 'latest_version_url': latest_version_url - } diff --git a/netbox/utilities/versions.py b/netbox/utilities/releases.py similarity index 77% rename from netbox/utilities/versions.py rename to netbox/utilities/releases.py index 72341c8f7..6fb422c00 100644 --- a/netbox/utilities/versions.py +++ b/netbox/utilities/releases.py @@ -4,9 +4,9 @@ from django.conf import settings from packaging import version -@cached(timeout=settings.GITHUB_VERSION_TIMEOUT if settings.GITHUB_VERSION_TIMEOUT > 0 else 1) +@cached(timeout=settings.GITHUB_CACHE_TIMEOUT, extra=settings.GITHUB_REPOSITORY_API) def get_releases(pre_releases=False): - url = 'https://api.github.com/repos/{}/releases'.format(settings.GITHUB_REPOSITORY) + url = '{}/releases'.format(settings.GITHUB_REPOSITORY_API) headers = { 'Accept': 'application/vnd.github.v3+json', } @@ -27,7 +27,7 @@ def get_releases(pre_releases=False): def get_latest_release(pre_releases=False): - if settings.GITHUB_VERSION_TIMEOUT > 0 and settings.GITHUB_REPOSITORY: + if settings.GITHUB_REPOSITORY_API: releases = get_releases(pre_releases) if releases: return max(releases) From 3a0849699fac7003bd5c6b0b232e18c5b5c0c91a Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Thu, 27 Feb 2020 18:15:31 +0100 Subject: [PATCH 05/11] Rename settings to be more generic, not GitHub-only --- docs/configuration/optional-settings.md | 8 ++++---- netbox/netbox/configuration.example.py | 4 ++-- netbox/netbox/settings.py | 22 +++++++++++----------- netbox/utilities/releases.py | 6 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/configuration/optional-settings.md b/docs/configuration/optional-settings.md index 5a3121960..652d10afc 100644 --- a/docs/configuration/optional-settings.md +++ b/docs/configuration/optional-settings.md @@ -157,17 +157,17 @@ Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce uni --- -## GITHUB_REPOSITORY_API +## UPDATE_REPO_URL Default: 'https://api.github.com/repos/netbox-community/netbox' -The releases of this repository are checked to detect new releases, which are shown on the home page of the web interface. You can change this to your own fork of the NetBox repository, or set it to `None` to disable the check. +The releases of this repository are checked to detect new releases, which are shown on the home page of the web interface. You can change this to your own fork of the NetBox repository, or set it to `None` to disable the check. The URL provided **must** be compatible with the GitHub API. --- -## GITHUB_CACHE_TIMEOUT +## UPDATE_CACHE_TIMEOUT -Default: 24 * 3600 +Default: 86,400 (24 hours) The number of seconds to retain the latest version that is fetched from the GitHub API before automatically invalidating it and fetching it from the API again. This must be set to at least one hour (3600 seconds). diff --git a/netbox/netbox/configuration.example.py b/netbox/netbox/configuration.example.py index b24db0f03..a90d286e7 100644 --- a/netbox/netbox/configuration.example.py +++ b/netbox/netbox/configuration.example.py @@ -126,10 +126,10 @@ EXEMPT_VIEW_PERMISSIONS = [ # This repository is used to check whether there is a new release of NetBox available. Set to None to disable the # version check. -GITHUB_REPOSITORY_API = 'https://api.github.com/repos/netbox-community/netbox' +UPDATE_REPO_URL = 'https://api.github.com/repos/netbox-community/netbox' # This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. -GITHUB_CACHE_TIMEOUT = 24 * 3600 +UPDATE_CACHE_TIMEOUT = 24 * 3600 # Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: # https://docs.djangoproject.com/en/stable/topics/logging/ diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 43b5428f9..ce0ed7ce7 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -80,9 +80,9 @@ DEVELOPER = getattr(configuration, 'DEVELOPER', False) EMAIL = getattr(configuration, 'EMAIL', {}) ENFORCE_GLOBAL_UNIQUE = getattr(configuration, 'ENFORCE_GLOBAL_UNIQUE', False) EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', []) -GITHUB_REPOSITORY_API = getattr(configuration, 'GITHUB_REPOSITORY_API', - 'https://api.github.com/repos/netbox-community/netbox') -GITHUB_CACHE_TIMEOUT = getattr(configuration, 'GITHUB_CACHE_TIMEOUT', 24 * 3600) +UPDATE_REPO_URL = getattr(configuration, 'UPDATE_REPO_URL', + 'https://api.github.com/repos/netbox-community/netbox') +UPDATE_CACHE_TIMEOUT = getattr(configuration, 'UPDATE_CACHE_TIMEOUT', 24 * 3600) LOGGING = getattr(configuration, 'LOGGING', {}) LOGIN_REQUIRED = getattr(configuration, 'LOGIN_REQUIRED', False) LOGIN_TIMEOUT = getattr(configuration, 'LOGIN_TIMEOUT', None) @@ -308,15 +308,15 @@ AUTHENTICATION_BACKENDS = [ ] # GitHub repository for version check -if GITHUB_REPOSITORY_API: - GITHUB_REPOSITORY_API = GITHUB_REPOSITORY_API.rstrip('/') +if UPDATE_REPO_URL: + UPDATE_REPO_URL = UPDATE_REPO_URL.rstrip('/') try: - scheme, netloc, path, query, fragment = urlsplit(GITHUB_REPOSITORY_API) + scheme, netloc, path, query, fragment = urlsplit(UPDATE_REPO_URL) except ValueError: - raise ImproperlyConfigured("GITHUB_REPOSITORY_API must be a valid URL") + raise ImproperlyConfigured("UPDATE_REPO_URL must be a valid URL") if scheme not in ('http', 'https'): - raise ImproperlyConfigured("GITHUB_REPOSITORY_API must be a valid http:// or https:// URL") + raise ImproperlyConfigured("UPDATE_REPO_URL must be a valid http:// or https:// URL") if not re.fullmatch(r'/repos/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+', path): raise ImproperlyConfigured( @@ -325,11 +325,11 @@ if GITHUB_REPOSITORY_API: ) if query or fragment: - raise ImproperlyConfigured("GITHUB_REPOSITORY_API may not contain a query or fragment") + raise ImproperlyConfigured("UPDATE_REPO_URL may not contain a query or fragment") # Enforce a cache timeout of at least an hour to protect GitHub -if GITHUB_CACHE_TIMEOUT < 3600: - raise ImproperlyConfigured("GITHUB_CACHE_TIMEOUT has to be at least 3600 seconds (1 hour)") +if UPDATE_CACHE_TIMEOUT < 3600: + raise ImproperlyConfigured("UPDATE_CACHE_TIMEOUT has to be at least 3600 seconds (1 hour)") # Internationalization LANGUAGE_CODE = 'en-us' diff --git a/netbox/utilities/releases.py b/netbox/utilities/releases.py index 6fb422c00..30ee8c295 100644 --- a/netbox/utilities/releases.py +++ b/netbox/utilities/releases.py @@ -4,9 +4,9 @@ from django.conf import settings from packaging import version -@cached(timeout=settings.GITHUB_CACHE_TIMEOUT, extra=settings.GITHUB_REPOSITORY_API) +@cached(timeout=settings.UPDATE_CACHE_TIMEOUT, extra=settings.UPDATE_REPO_URL) def get_releases(pre_releases=False): - url = '{}/releases'.format(settings.GITHUB_REPOSITORY_API) + url = '{}/releases'.format(settings.UPDATE_REPO_URL) headers = { 'Accept': 'application/vnd.github.v3+json', } @@ -27,7 +27,7 @@ def get_releases(pre_releases=False): def get_latest_release(pre_releases=False): - if settings.GITHUB_REPOSITORY_API: + if settings.UPDATE_REPO_URL: releases = get_releases(pre_releases) if releases: return max(releases) From 8d92089487c8116edf4fdfb0aa825ce9c29e308a Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Thu, 27 Feb 2020 18:18:05 +0100 Subject: [PATCH 06/11] Improve comments and error message on invalid characters in URL --- netbox/netbox/settings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index ce0ed7ce7..aaac8a153 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -324,8 +324,9 @@ if UPDATE_REPO_URL: "'https://api.github.com/repos//'" ) + # Don't allow ? (query) and # (fragment) in the URL if query or fragment: - raise ImproperlyConfigured("UPDATE_REPO_URL may not contain a query or fragment") + raise ImproperlyConfigured("UPDATE_REPO_URL may not contain a ? (query) or # (fragment)") # Enforce a cache timeout of at least an hour to protect GitHub if UPDATE_CACHE_TIMEOUT < 3600: From 0de7f4712f82ec27ccf48685570b984d1a987fad Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Thu, 27 Feb 2020 18:20:32 +0100 Subject: [PATCH 07/11] Fix check for permissions --- netbox/netbox/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index 9afa9c73a..7634893a7 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -246,7 +246,7 @@ class HomeView(View): new_release = None new_release_url = None - if request.user.is_staff: + if request.user.is_staff or request.user.is_superuser: # Only check for new releases if the current user might be able to do anything about it latest_release, github_url = get_latest_release() if isinstance(latest_release, version.Version): From 22ac9f63a122bf16fcb58915a83823855152de27 Mon Sep 17 00:00:00 2001 From: Sander Steffann Date: Thu, 27 Feb 2020 18:21:31 +0100 Subject: [PATCH 08/11] Don't overwrite the header block, append to it --- netbox/templates/home.html | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/templates/home.html b/netbox/templates/home.html index ed6ef06d6..b560d8894 100644 --- a/netbox/templates/home.html +++ b/netbox/templates/home.html @@ -2,6 +2,7 @@ {% load helpers %} {% block header %} + {{ block.super }} {% if new_release %}