prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  False version status in admin dashboard for AirGapped environments
  **Describe the bug**
  In an AirGapped environment with `AUTHENTIK_DISABLE_UPDATE_CHECK=true`, or when the version check has not yet been performed, the version tile on the admin dashboard will always state its `Up-to-date!` which may not actually be the case.
  
  **To Reproduce**
  Steps to reproduce the behavior:
  
  1. Deploy a fresh Authentik installation on an older version (e.g. `2023.10.7`) and ensure  `AUTHENTIK_DISABLE_UPDATE_CHECK=true` is set.
  2. Go to the admin dashboard
  3. Observe the version tile stating proudly that its up-to-date.
  
  **Expected behavior**
  Not incorrectly stating its up-to-date as that would give a false sense of security.
  
  **Screenshots**
  ![image](https://github.com/goauthentik/authentik/assets/68224306/0a470c2b-73f7-4ba1-ad83-7e35a7f9a053)
  
  **Logs**
  N/a
  
  **Version and Deployment (please complete the following information):**
  
  -   authentik version: 2024.2.0
  -   Deployment: docker-compose
  
  **Additional context**
  N/a
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `authentik/admin/api/version.py`
  Content:
  ```
  1 """authentik administration overview"""
  2 
  3 from django.core.cache import cache
  4 from drf_spectacular.utils import extend_schema
  5 from packaging.version import parse
  6 from rest_framework.fields import SerializerMethodField
  7 from rest_framework.permissions import IsAuthenticated
  8 from rest_framework.request import Request
  9 from rest_framework.response import Response
  10 from rest_framework.views import APIView
  11 
  12 from authentik import __version__, get_build_hash
  13 from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version
  14 from authentik.core.api.utils import PassiveSerializer
  15 
  16 
  17 class VersionSerializer(PassiveSerializer):
  18     """Get running and latest version."""
  19 
  20     version_current = SerializerMethodField()
  21     version_latest = SerializerMethodField()
  22     build_hash = SerializerMethodField()
  23     outdated = SerializerMethodField()
  24 
  25     def get_build_hash(self, _) -> str:
  26         """Get build hash, if version is not latest or released"""
  27         return get_build_hash()
  28 
  29     def get_version_current(self, _) -> str:
  30         """Get current version"""
  31         return __version__
  32 
  33     def get_version_latest(self, _) -> str:
  34         """Get latest version from cache"""
  35         version_in_cache = cache.get(VERSION_CACHE_KEY)
  36         if not version_in_cache:  # pragma: no cover
  37             update_latest_version.delay()
  38             return __version__
  39         return version_in_cache
  40 
  41     def get_outdated(self, instance) -> bool:
  42         """Check if we're running the latest version"""
  43         return parse(self.get_version_current(instance)) < parse(self.get_version_latest(instance))
  44 
  45 
  46 class VersionView(APIView):
  47     """Get running and latest version."""
  48 
  49     permission_classes = [IsAuthenticated]
  50     pagination_class = None
  51     filter_backends = []
  52 
  53     @extend_schema(responses={200: VersionSerializer(many=False)})
  54     def get(self, request: Request) -> Response:
  55         """Get running and latest version."""
  56         return Response(VersionSerializer(True).data)
  57
  ```
  
  Path: `authentik/admin/tasks.py`
  Content:
  ```
  1 """authentik admin tasks"""
  2 
  3 import re
  4 
  5 from django.core.cache import cache
  6 from django.core.validators import URLValidator
  7 from django.db import DatabaseError, InternalError, ProgrammingError
  8 from packaging.version import parse
  9 from requests import RequestException
  10 from structlog.stdlib import get_logger
  11 
  12 from authentik import __version__, get_build_hash
  13 from authentik.admin.apps import PROM_INFO
  14 from authentik.events.models import Event, EventAction, Notification
  15 from authentik.events.system_tasks import SystemTask, TaskStatus, prefill_task
  16 from authentik.lib.config import CONFIG
  17 from authentik.lib.utils.http import get_http_session
  18 from authentik.root.celery import CELERY_APP
  19 
  20 LOGGER = get_logger()
  21 VERSION_CACHE_KEY = "authentik_latest_version"
  22 VERSION_CACHE_TIMEOUT = 8 * 60 * 60  # 8 hours
  23 # Chop of the first ^ because we want to search the entire string
  24 URL_FINDER = URLValidator.regex.pattern[1:]
  25 LOCAL_VERSION = parse(__version__)
  26 
  27 
  28 def _set_prom_info():
  29     """Set prometheus info for version"""
  30     PROM_INFO.info(
  31         {
  32             "version": __version__,
  33             "latest": cache.get(VERSION_CACHE_KEY, ""),
  34             "build_hash": get_build_hash(),
  35         }
  36     )
  37 
  38 
  39 @CELERY_APP.task(
  40     throws=(DatabaseError, ProgrammingError, InternalError),
  41 )
  42 def clear_update_notifications():
  43     """Clear update notifications on startup if the notification was for the version
  44     we're running now."""
  45     for notification in Notification.objects.filter(event__action=EventAction.UPDATE_AVAILABLE):
  46         if "new_version" not in notification.event.context:
  47             continue
  48         notification_version = notification.event.context["new_version"]
  49         if LOCAL_VERSION >= parse(notification_version):
  50             notification.delete()
  51 
  52 
  53 @CELERY_APP.task(bind=True, base=SystemTask)
  54 @prefill_task
  55 def update_latest_version(self: SystemTask):
  56     """Update latest version info"""
  57     if CONFIG.get_bool("disable_update_check"):
  58         cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT)
  59         self.set_status(TaskStatus.WARNING, "Version check disabled.")
  60         return
  61     try:
  62         response = get_http_session().get(
  63             "https://version.goauthentik.io/version.json",
  64         )
  65         response.raise_for_status()
  66         data = response.json()
  67         upstream_version = data.get("stable", {}).get("version")
  68         cache.set(VERSION_CACHE_KEY, upstream_version, VERSION_CACHE_TIMEOUT)
  69         self.set_status(TaskStatus.SUCCESSFUL, "Successfully updated latest Version")
  70         _set_prom_info()
  71         # Check if upstream version is newer than what we're running,
  72         # and if no event exists yet, create one.
  73         if LOCAL_VERSION < parse(upstream_version):
  74             # Event has already been created, don't create duplicate
  75             if Event.objects.filter(
  76                 action=EventAction.UPDATE_AVAILABLE,
  77                 context__new_version=upstream_version,
  78             ).exists():
  79                 return
  80             event_dict = {"new_version": upstream_version}
  81             if match := re.search(URL_FINDER, data.get("stable", {}).get("changelog", "")):
  82                 event_dict["message"] = f"Changelog: {match.group()}"
  83             Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save()
  84     except (RequestException, IndexError) as exc:
  85         cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT)
  86         self.set_error(exc)
  87 
  88 
  89 _set_prom_info()
  90
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/authentik/admin/api/version.py b/authentik/admin/api/version.py
  --- a/authentik/admin/api/version.py
  +++ b/authentik/admin/api/version.py
  @@ -10,7 +10,7 @@
   from rest_framework.views import APIView
   
   from authentik import __version__, get_build_hash
  -from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version
  +from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version
   from authentik.core.api.utils import PassiveSerializer
   
   
  @@ -19,6 +19,7 @@
   
       version_current = SerializerMethodField()
       version_latest = SerializerMethodField()
  +    version_latest_valid = SerializerMethodField()
       build_hash = SerializerMethodField()
       outdated = SerializerMethodField()
   
  @@ -38,6 +39,10 @@
               return __version__
           return version_in_cache
   
  +    def get_version_latest_valid(self, _) -> str:
  +        """Check if latest version is valid"""
  +        return cache.get(VERSION_CACHE_KEY) != VERSION_NULL
  +
       def get_outdated(self, instance) -> bool:
           """Check if we're running the latest version"""
           return parse(self.get_version_current(instance)) < parse(self.get_version_latest(instance))
  diff --git a/authentik/admin/tasks.py b/authentik/admin/tasks.py
  --- a/authentik/admin/tasks.py
  +++ b/authentik/admin/tasks.py
  @@ -18,6 +18,7 @@
   from authentik.root.celery import CELERY_APP
   
   LOGGER = get_logger()
  +VERSION_NULL = "0.0.0"
   VERSION_CACHE_KEY = "authentik_latest_version"
   VERSION_CACHE_TIMEOUT = 8 * 60 * 60  # 8 hours
   # Chop of the first ^ because we want to search the entire string
  @@ -55,7 +56,7 @@
   def update_latest_version(self: SystemTask):
       """Update latest version info"""
       if CONFIG.get_bool("disable_update_check"):
  -        cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT)
  +        cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)
           self.set_status(TaskStatus.WARNING, "Version check disabled.")
           return
       try:
  @@ -82,7 +83,7 @@
                   event_dict["message"] = f"Changelog: {match.group()}"
               Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save()
       except (RequestException, IndexError) as exc:
  -        cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT)
  +        cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)
           self.set_error(exc)
  
verification_info: {"golden_diff": "diff --git a/authentik/admin/api/version.py b/authentik/admin/api/version.py\n--- a/authentik/admin/api/version.py\n+++ b/authentik/admin/api/version.py\n@@ -10,7 +10,7 @@\n from rest_framework.views import APIView\n \n from authentik import __version__, get_build_hash\n-from authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version\n+from authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version\n from authentik.core.api.utils import PassiveSerializer\n \n \n@@ -19,6 +19,7 @@\n \n     version_current = SerializerMethodField()\n     version_latest = SerializerMethodField()\n+    version_latest_valid = SerializerMethodField()\n     build_hash = SerializerMethodField()\n     outdated = SerializerMethodField()\n \n@@ -38,6 +39,10 @@\n             return __version__\n         return version_in_cache\n \n+    def get_version_latest_valid(self, _) -> str:\n+        \"\"\"Check if latest version is valid\"\"\"\n+        return cache.get(VERSION_CACHE_KEY) != VERSION_NULL\n+\n     def get_outdated(self, instance) -> bool:\n         \"\"\"Check if we're running the latest version\"\"\"\n         return parse(self.get_version_current(instance)) < parse(self.get_version_latest(instance))\ndiff --git a/authentik/admin/tasks.py b/authentik/admin/tasks.py\n--- a/authentik/admin/tasks.py\n+++ b/authentik/admin/tasks.py\n@@ -18,6 +18,7 @@\n from authentik.root.celery import CELERY_APP\n \n LOGGER = get_logger()\n+VERSION_NULL = \"0.0.0\"\n VERSION_CACHE_KEY = \"authentik_latest_version\"\n VERSION_CACHE_TIMEOUT = 8 * 60 * 60  # 8 hours\n # Chop of the first ^ because we want to search the entire string\n@@ -55,7 +56,7 @@\n def update_latest_version(self: SystemTask):\n     \"\"\"Update latest version info\"\"\"\n     if CONFIG.get_bool(\"disable_update_check\"):\n-        cache.set(VERSION_CACHE_KEY, \"0.0.0\", VERSION_CACHE_TIMEOUT)\n+        cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)\n         self.set_status(TaskStatus.WARNING, \"Version check disabled.\")\n         return\n     try:\n@@ -82,7 +83,7 @@\n                 event_dict[\"message\"] = f\"Changelog: {match.group()}\"\n             Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save()\n     except (RequestException, IndexError) as exc:\n-        cache.set(VERSION_CACHE_KEY, \"0.0.0\", VERSION_CACHE_TIMEOUT)\n+        cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)\n         self.set_error(exc)\n", "issue": "False version status in admin dashboard for AirGapped environments\n**Describe the bug**\r\nIn an AirGapped environment with `AUTHENTIK_DISABLE_UPDATE_CHECK=true`, or when the version check has not yet been performed, the version tile on the admin dashboard will always state its `Up-to-date!` which may not actually be the case.\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n\r\n1. Deploy a fresh Authentik installation on an older version (e.g. `2023.10.7`) and ensure  `AUTHENTIK_DISABLE_UPDATE_CHECK=true` is set.\r\n2. Go to the admin dashboard\r\n3. Observe the version tile stating proudly that its up-to-date.\r\n\r\n**Expected behavior**\r\nNot incorrectly stating its up-to-date as that would give a false sense of security.\r\n\r\n**Screenshots**\r\n![image](https://github.com/goauthentik/authentik/assets/68224306/0a470c2b-73f7-4ba1-ad83-7e35a7f9a053)\r\n\r\n**Logs**\r\nN/a\r\n\r\n**Version and Deployment (please complete the following information):**\r\n\r\n-   authentik version: 2024.2.0\r\n-   Deployment: docker-compose\r\n\r\n**Additional context**\r\nN/a\r\n\n", "before_files": [{"content": "\"\"\"authentik administration overview\"\"\"\n\nfrom django.core.cache import cache\nfrom drf_spectacular.utils import extend_schema\nfrom packaging.version import parse\nfrom rest_framework.fields import SerializerMethodField\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.request import Request\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nfrom authentik import __version__, get_build_hash\nfrom authentik.admin.tasks import VERSION_CACHE_KEY, update_latest_version\nfrom authentik.core.api.utils import PassiveSerializer\n\n\nclass VersionSerializer(PassiveSerializer):\n    \"\"\"Get running and latest version.\"\"\"\n\n    version_current = SerializerMethodField()\n    version_latest = SerializerMethodField()\n    build_hash = SerializerMethodField()\n    outdated = SerializerMethodField()\n\n    def get_build_hash(self, _) -> str:\n        \"\"\"Get build hash, if version is not latest or released\"\"\"\n        return get_build_hash()\n\n    def get_version_current(self, _) -> str:\n        \"\"\"Get current version\"\"\"\n        return __version__\n\n    def get_version_latest(self, _) -> str:\n        \"\"\"Get latest version from cache\"\"\"\n        version_in_cache = cache.get(VERSION_CACHE_KEY)\n        if not version_in_cache:  # pragma: no cover\n            update_latest_version.delay()\n            return __version__\n        return version_in_cache\n\n    def get_outdated(self, instance) -> bool:\n        \"\"\"Check if we're running the latest version\"\"\"\n        return parse(self.get_version_current(instance)) < parse(self.get_version_latest(instance))\n\n\nclass VersionView(APIView):\n    \"\"\"Get running and latest version.\"\"\"\n\n    permission_classes = [IsAuthenticated]\n    pagination_class = None\n    filter_backends = []\n\n    @extend_schema(responses={200: VersionSerializer(many=False)})\n    def get(self, request: Request) -> Response:\n        \"\"\"Get running and latest version.\"\"\"\n        return Response(VersionSerializer(True).data)\n", "path": "authentik/admin/api/version.py"}, {"content": "\"\"\"authentik admin tasks\"\"\"\n\nimport re\n\nfrom django.core.cache import cache\nfrom django.core.validators import URLValidator\nfrom django.db import DatabaseError, InternalError, ProgrammingError\nfrom packaging.version import parse\nfrom requests import RequestException\nfrom structlog.stdlib import get_logger\n\nfrom authentik import __version__, get_build_hash\nfrom authentik.admin.apps import PROM_INFO\nfrom authentik.events.models import Event, EventAction, Notification\nfrom authentik.events.system_tasks import SystemTask, TaskStatus, prefill_task\nfrom authentik.lib.config import CONFIG\nfrom authentik.lib.utils.http import get_http_session\nfrom authentik.root.celery import CELERY_APP\n\nLOGGER = get_logger()\nVERSION_CACHE_KEY = \"authentik_latest_version\"\nVERSION_CACHE_TIMEOUT = 8 * 60 * 60  # 8 hours\n# Chop of the first ^ because we want to search the entire string\nURL_FINDER = URLValidator.regex.pattern[1:]\nLOCAL_VERSION = parse(__version__)\n\n\ndef _set_prom_info():\n    \"\"\"Set prometheus info for version\"\"\"\n    PROM_INFO.info(\n        {\n            \"version\": __version__,\n            \"latest\": cache.get(VERSION_CACHE_KEY, \"\"),\n            \"build_hash\": get_build_hash(),\n        }\n    )\n\n\n@CELERY_APP.task(\n    throws=(DatabaseError, ProgrammingError, InternalError),\n)\ndef clear_update_notifications():\n    \"\"\"Clear update notifications on startup if the notification was for the version\n    we're running now.\"\"\"\n    for notification in Notification.objects.filter(event__action=EventAction.UPDATE_AVAILABLE):\n        if \"new_version\" not in notification.event.context:\n            continue\n        notification_version = notification.event.context[\"new_version\"]\n        if LOCAL_VERSION >= parse(notification_version):\n            notification.delete()\n\n\n@CELERY_APP.task(bind=True, base=SystemTask)\n@prefill_task\ndef update_latest_version(self: SystemTask):\n    \"\"\"Update latest version info\"\"\"\n    if CONFIG.get_bool(\"disable_update_check\"):\n        cache.set(VERSION_CACHE_KEY, \"0.0.0\", VERSION_CACHE_TIMEOUT)\n        self.set_status(TaskStatus.WARNING, \"Version check disabled.\")\n        return\n    try:\n        response = get_http_session().get(\n            \"https://version.goauthentik.io/version.json\",\n        )\n        response.raise_for_status()\n        data = response.json()\n        upstream_version = data.get(\"stable\", {}).get(\"version\")\n        cache.set(VERSION_CACHE_KEY, upstream_version, VERSION_CACHE_TIMEOUT)\n        self.set_status(TaskStatus.SUCCESSFUL, \"Successfully updated latest Version\")\n        _set_prom_info()\n        # Check if upstream version is newer than what we're running,\n        # and if no event exists yet, create one.\n        if LOCAL_VERSION < parse(upstream_version):\n            # Event has already been created, don't create duplicate\n            if Event.objects.filter(\n                action=EventAction.UPDATE_AVAILABLE,\n                context__new_version=upstream_version,\n            ).exists():\n                return\n            event_dict = {\"new_version\": upstream_version}\n            if match := re.search(URL_FINDER, data.get(\"stable\", {}).get(\"changelog\", \"\")):\n                event_dict[\"message\"] = f\"Changelog: {match.group()}\"\n            Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save()\n    except (RequestException, IndexError) as exc:\n        cache.set(VERSION_CACHE_KEY, \"0.0.0\", VERSION_CACHE_TIMEOUT)\n        self.set_error(exc)\n\n\n_set_prom_info()\n", "path": "authentik/admin/tasks.py"}], "after_files": [{"content": "\"\"\"authentik administration overview\"\"\"\n\nfrom django.core.cache import cache\nfrom drf_spectacular.utils import extend_schema\nfrom packaging.version import parse\nfrom rest_framework.fields import SerializerMethodField\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.request import Request\nfrom rest_framework.response import Response\nfrom rest_framework.views import APIView\n\nfrom authentik import __version__, get_build_hash\nfrom authentik.admin.tasks import VERSION_CACHE_KEY, VERSION_NULL, update_latest_version\nfrom authentik.core.api.utils import PassiveSerializer\n\n\nclass VersionSerializer(PassiveSerializer):\n    \"\"\"Get running and latest version.\"\"\"\n\n    version_current = SerializerMethodField()\n    version_latest = SerializerMethodField()\n    version_latest_valid = SerializerMethodField()\n    build_hash = SerializerMethodField()\n    outdated = SerializerMethodField()\n\n    def get_build_hash(self, _) -> str:\n        \"\"\"Get build hash, if version is not latest or released\"\"\"\n        return get_build_hash()\n\n    def get_version_current(self, _) -> str:\n        \"\"\"Get current version\"\"\"\n        return __version__\n\n    def get_version_latest(self, _) -> str:\n        \"\"\"Get latest version from cache\"\"\"\n        version_in_cache = cache.get(VERSION_CACHE_KEY)\n        if not version_in_cache:  # pragma: no cover\n            update_latest_version.delay()\n            return __version__\n        return version_in_cache\n\n    def get_version_latest_valid(self, _) -> str:\n        \"\"\"Check if latest version is valid\"\"\"\n        return cache.get(VERSION_CACHE_KEY) != VERSION_NULL\n\n    def get_outdated(self, instance) -> bool:\n        \"\"\"Check if we're running the latest version\"\"\"\n        return parse(self.get_version_current(instance)) < parse(self.get_version_latest(instance))\n\n\nclass VersionView(APIView):\n    \"\"\"Get running and latest version.\"\"\"\n\n    permission_classes = [IsAuthenticated]\n    pagination_class = None\n    filter_backends = []\n\n    @extend_schema(responses={200: VersionSerializer(many=False)})\n    def get(self, request: Request) -> Response:\n        \"\"\"Get running and latest version.\"\"\"\n        return Response(VersionSerializer(True).data)\n", "path": "authentik/admin/api/version.py"}, {"content": "\"\"\"authentik admin tasks\"\"\"\n\nimport re\n\nfrom django.core.cache import cache\nfrom django.core.validators import URLValidator\nfrom django.db import DatabaseError, InternalError, ProgrammingError\nfrom packaging.version import parse\nfrom requests import RequestException\nfrom structlog.stdlib import get_logger\n\nfrom authentik import __version__, get_build_hash\nfrom authentik.admin.apps import PROM_INFO\nfrom authentik.events.models import Event, EventAction, Notification\nfrom authentik.events.system_tasks import SystemTask, TaskStatus, prefill_task\nfrom authentik.lib.config import CONFIG\nfrom authentik.lib.utils.http import get_http_session\nfrom authentik.root.celery import CELERY_APP\n\nLOGGER = get_logger()\nVERSION_NULL = \"0.0.0\"\nVERSION_CACHE_KEY = \"authentik_latest_version\"\nVERSION_CACHE_TIMEOUT = 8 * 60 * 60  # 8 hours\n# Chop of the first ^ because we want to search the entire string\nURL_FINDER = URLValidator.regex.pattern[1:]\nLOCAL_VERSION = parse(__version__)\n\n\ndef _set_prom_info():\n    \"\"\"Set prometheus info for version\"\"\"\n    PROM_INFO.info(\n        {\n            \"version\": __version__,\n            \"latest\": cache.get(VERSION_CACHE_KEY, \"\"),\n            \"build_hash\": get_build_hash(),\n        }\n    )\n\n\n@CELERY_APP.task(\n    throws=(DatabaseError, ProgrammingError, InternalError),\n)\ndef clear_update_notifications():\n    \"\"\"Clear update notifications on startup if the notification was for the version\n    we're running now.\"\"\"\n    for notification in Notification.objects.filter(event__action=EventAction.UPDATE_AVAILABLE):\n        if \"new_version\" not in notification.event.context:\n            continue\n        notification_version = notification.event.context[\"new_version\"]\n        if LOCAL_VERSION >= parse(notification_version):\n            notification.delete()\n\n\n@CELERY_APP.task(bind=True, base=SystemTask)\n@prefill_task\ndef update_latest_version(self: SystemTask):\n    \"\"\"Update latest version info\"\"\"\n    if CONFIG.get_bool(\"disable_update_check\"):\n        cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)\n        self.set_status(TaskStatus.WARNING, \"Version check disabled.\")\n        return\n    try:\n        response = get_http_session().get(\n            \"https://version.goauthentik.io/version.json\",\n        )\n        response.raise_for_status()\n        data = response.json()\n        upstream_version = data.get(\"stable\", {}).get(\"version\")\n        cache.set(VERSION_CACHE_KEY, upstream_version, VERSION_CACHE_TIMEOUT)\n        self.set_status(TaskStatus.SUCCESSFUL, \"Successfully updated latest Version\")\n        _set_prom_info()\n        # Check if upstream version is newer than what we're running,\n        # and if no event exists yet, create one.\n        if LOCAL_VERSION < parse(upstream_version):\n            # Event has already been created, don't create duplicate\n            if Event.objects.filter(\n                action=EventAction.UPDATE_AVAILABLE,\n                context__new_version=upstream_version,\n            ).exists():\n                return\n            event_dict = {\"new_version\": upstream_version}\n            if match := re.search(URL_FINDER, data.get(\"stable\", {}).get(\"changelog\", \"\")):\n                event_dict[\"message\"] = f\"Changelog: {match.group()}\"\n            Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save()\n    except (RequestException, IndexError) as exc:\n        cache.set(VERSION_CACHE_KEY, VERSION_NULL, VERSION_CACHE_TIMEOUT)\n        self.set_error(exc)\n\n\n_set_prom_info()\n", "path": "authentik/admin/tasks.py"}]}