diff --git a/Pipfile.lock b/Pipfile.lock index 9d9c1fedd..f77949d16 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -74,18 +74,18 @@ }, "boto3": { "hashes": [ - "sha256:b5052144034e490358c659d0e480c17a4e604fd3aee9a97ddfe6e361a245a4a5", - "sha256:efd6c96c98900e9fbf217f13cb58f59b793e51f69a1ce61817eefd31f17c6ef5" + "sha256:3f26aad4c6b238055d17fd662620284ffb4ced542ed9a2f7f9df65d97a3f1190", + "sha256:47151ed571c316458f4931cd2422995ba0c9f6818c5df7d75f49fc845208e42e" ], "index": "pypi", - "version": "==1.16.55" + "version": "==1.16.56" }, "botocore": { "hashes": [ - "sha256:760d0c16c1474c2a46e3fa45e33ae7457b5cab7410737ab1692340ade764cc73", - "sha256:b34327d84b3bb5620fb54603677a9a973b167290c2c1e7ab69c4a46b201c6d46" + "sha256:01496e4c2c06aab79689f2c345a0e2cceb5fe1da7858a7e7df189bcf97703223", + "sha256:a37d073c2f166753cc3799e77d87d4096e24433fcca5e7c8cc8e77e5dbfe60e9" ], - "version": "==1.19.55" + "version": "==1.19.56" }, "cachetools": { "hashes": [ diff --git a/authentik/admin/api/tasks.py b/authentik/admin/api/tasks.py index 3c4075084..ddeed8fb9 100644 --- a/authentik/admin/api/tasks.py +++ b/authentik/admin/api/tasks.py @@ -14,7 +14,7 @@ from rest_framework.response import Response from rest_framework.serializers import Serializer from rest_framework.viewsets import ViewSet -from authentik.lib.tasks import TaskInfo +from authentik.events.monitored_tasks import TaskInfo class TaskSerializer(Serializer): diff --git a/authentik/admin/tasks.py b/authentik/admin/tasks.py index e4c7efed6..336cfa37a 100644 --- a/authentik/admin/tasks.py +++ b/authentik/admin/tasks.py @@ -6,7 +6,7 @@ from structlog.stdlib import get_logger from authentik import __version__ from authentik.events.models import Event, EventAction -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.root.celery import CELERY_APP LOGGER = get_logger() diff --git a/authentik/admin/views/tasks.py b/authentik/admin/views/tasks.py index 44b96c8e9..40dfa74c1 100644 --- a/authentik/admin/views/tasks.py +++ b/authentik/admin/views/tasks.py @@ -4,7 +4,7 @@ from typing import Any, Dict from django.views.generic.base import TemplateView from authentik.admin.mixins import AdminRequiredMixin -from authentik.lib.tasks import TaskInfo, TaskResultStatus +from authentik.events.monitored_tasks import TaskInfo, TaskResultStatus class TaskListView(AdminRequiredMixin, TemplateView): diff --git a/authentik/core/tasks.py b/authentik/core/tasks.py index 168255b24..aaf2c3aef 100644 --- a/authentik/core/tasks.py +++ b/authentik/core/tasks.py @@ -11,7 +11,7 @@ from django.utils.timezone import now from structlog.stdlib import get_logger from authentik.core.models import ExpiringModel -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.root.celery import CELERY_APP LOGGER = get_logger() diff --git a/authentik/events/models.py b/authentik/events/models.py index 2e5875f46..b28a71423 100644 --- a/authentik/events/models.py +++ b/authentik/events/models.py @@ -22,7 +22,6 @@ from authentik.events.utils import cleanse_dict, get_user, sanitize_dict from authentik.lib.sentry import SentryIgnoredException from authentik.lib.utils.http import get_client_ip from authentik.policies.models import PolicyBindingModel -from authentik.stages.email.tasks import send_mail from authentik.stages.email.utils import TemplateEmailMessage LOGGER = get_logger("authentik.events") @@ -57,6 +56,9 @@ class EventAction(models.TextChoices): POLICY_EXCEPTION = "policy_exception" PROPERTY_MAPPING_EXCEPTION = "property_mapping_exception" + SYSTEM_TASK_EXECUTION = "system_task_execution" + SYSTEM_TASK_EXCEPTION = "system_task_exception" + CONFIGURATION_ERROR = "configuration_error" MODEL_CREATED = "model_created" @@ -280,6 +282,8 @@ class NotificationTransport(models.Model): ) # Email is sent directly here, as the call to send() should have been from a task. try: + from authentik.stages.email.tasks import send_mail + # pyright: reportGeneralTypeIssues=false return send_mail(mail.__dict__) # pylint: disable=no-value-for-parameter except (SMTPException, ConnectionError, OSError) as exc: diff --git a/authentik/lib/tasks.py b/authentik/events/monitored_tasks.py similarity index 89% rename from authentik/lib/tasks.py rename to authentik/events/monitored_tasks.py index 132d03a5e..b6d66bece 100644 --- a/authentik/lib/tasks.py +++ b/authentik/events/monitored_tasks.py @@ -8,6 +8,8 @@ from typing import Any, Dict, List, Optional from celery import Task from django.core.cache import cache +from authentik.events.models import Event, EventAction + class TaskResultStatus(Enum): """Possible states of tasks""" @@ -122,6 +124,13 @@ class MonitoredTask(Task): task_call_args=args, task_call_kwargs=kwargs, ).save(self.result_timeout_hours) + Event.new( + EventAction.SYSTEM_TASK_EXECUTION, + message=( + f"Task {self.__name__} finished successfully: " + "\n".join(self._result.messages) + ), + ).save() return super().after_return(status, retval, task_id, args, kwargs, einfo=einfo) # pylint: disable=too-many-arguments @@ -138,6 +147,13 @@ class MonitoredTask(Task): task_call_args=args, task_call_kwargs=kwargs, ).save(self.result_timeout_hours) + Event.new( + EventAction.SYSTEM_TASK_EXCEPTION, + message=( + f"Task {self.__name__} encountered an error: " + "\n".join(self._result.messages) + ), + ).save() return super().on_failure(exc, task_id, args, kwargs, einfo=einfo) def run(self, *args, **kwargs): diff --git a/authentik/events/tasks.py b/authentik/events/tasks.py index ad13c610b..1f30f73a3 100644 --- a/authentik/events/tasks.py +++ b/authentik/events/tasks.py @@ -9,7 +9,7 @@ from authentik.events.models import ( NotificationTransport, NotificationTransportError, ) -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.policies.engine import PolicyEngine, PolicyEngineMode from authentik.policies.models import PolicyBinding from authentik.root.celery import CELERY_APP diff --git a/authentik/events/tests/test_notifications.py b/authentik/events/tests/test_notifications.py index eccf3e182..98c23b5fb 100644 --- a/authentik/events/tests/test_notifications.py +++ b/authentik/events/tests/test_notifications.py @@ -87,4 +87,4 @@ class TestEventsNotifications(TestCase): "authentik.events.models.NotificationTransport.send", execute_mock ): Event.new(EventAction.CUSTOM_PREFIX).save() - self.assertEqual(passes.call_count, 0) + self.assertEqual(passes.call_count, 1) diff --git a/authentik/outposts/tasks.py b/authentik/outposts/tasks.py index 8ce64c77a..b187216f3 100644 --- a/authentik/outposts/tasks.py +++ b/authentik/outposts/tasks.py @@ -8,7 +8,7 @@ from django.db.models.base import Model from django.utils.text import slugify from structlog.stdlib import get_logger -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.lib.utils.reflection import path_to_class from authentik.outposts.controllers.base import ControllerException from authentik.outposts.models import ( diff --git a/authentik/policies/reputation/tasks.py b/authentik/policies/reputation/tasks.py index 17781ca1c..a6fcf2b38 100644 --- a/authentik/policies/reputation/tasks.py +++ b/authentik/policies/reputation/tasks.py @@ -3,7 +3,7 @@ from django.core.cache import cache from structlog.stdlib import get_logger from authentik.core.models import User -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.policies.reputation.models import IPReputation, UserReputation from authentik.policies.reputation.signals import ( CACHE_KEY_IP_PREFIX, diff --git a/authentik/sources/ldap/tasks.py b/authentik/sources/ldap/tasks.py index fcb47c756..29ac1696f 100644 --- a/authentik/sources/ldap/tasks.py +++ b/authentik/sources/ldap/tasks.py @@ -5,7 +5,7 @@ from django.core.cache import cache from django.utils.text import slugify from ldap3.core.exceptions import LDAPException -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.root.celery import CELERY_APP from authentik.sources.ldap.models import LDAPSource from authentik.sources.ldap.sync import LDAPSynchronizer diff --git a/authentik/sources/saml/tasks.py b/authentik/sources/saml/tasks.py index 55dff9c5b..4ebbddba9 100644 --- a/authentik/sources/saml/tasks.py +++ b/authentik/sources/saml/tasks.py @@ -3,7 +3,7 @@ from django.utils.timezone import now from structlog.stdlib import get_logger from authentik.core.models import User -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.lib.utils.time import timedelta_from_string from authentik.root.celery import CELERY_APP from authentik.sources.saml.models import SAMLSource diff --git a/authentik/stages/email/tasks.py b/authentik/stages/email/tasks.py index 84cb73134..38fafdeeb 100644 --- a/authentik/stages/email/tasks.py +++ b/authentik/stages/email/tasks.py @@ -9,7 +9,7 @@ from django.core.mail.utils import DNS_NAME from django.utils.text import slugify from structlog.stdlib import get_logger -from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus +from authentik.events.monitored_tasks import MonitoredTask, TaskResult, TaskResultStatus from authentik.root.celery import CELERY_APP from authentik.stages.email.models import EmailStage diff --git a/swagger.yaml b/swagger.yaml index 8e0539760..548a5e4cd 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -7584,6 +7584,8 @@ definitions: - policy_execution - policy_exception - property_mapping_exception + - system_task_execution + - system_task_exception - configuration_error - model_created - model_updated @@ -8300,6 +8302,8 @@ definitions: - policy_execution - policy_exception - property_mapping_exception + - system_task_execution + - system_task_exception - configuration_error - model_created - model_updated diff --git a/web/package-lock.json b/web/package-lock.json index 1b7b52024..2b5ac2d81 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -38,9 +38,9 @@ } }, "@eslint/eslintrc": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", - "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", + "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -50,7 +50,7 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, @@ -1074,13 +1074,13 @@ "dev": true }, "eslint": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.17.0.tgz", - "integrity": "sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", + "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.2", + "@eslint/eslintrc": "^0.3.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1104,7 +1104,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash": "^4.17.20", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -2674,9 +2674,9 @@ } }, "rollup": { - "version": "2.36.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.36.1.tgz", - "integrity": "sha512-eAfqho8dyzuVvrGqpR0ITgEdq0zG2QJeWYh+HeuTbpcaXk8vNFc48B7bJa1xYosTCKx0CuW+447oQOW8HgBIZQ==", + "version": "2.36.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.36.2.tgz", + "integrity": "sha512-qjjiuJKb+/8n0EZyQYVW+gFU4bNRBcZaXVzUgSVrGw0HlQBlK2aWyaOMMs1Ufic1jV69b9kW3u3i9B+hISDm3A==", "requires": { "fsevents": "~2.1.2" } @@ -3191,9 +3191,9 @@ } }, "table": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.6.tgz", - "integrity": "sha512-OInCtPmDNieVBkVFi6C8RwU2S2H0h8mF3e3TQK4nreaUNCpooQUkI+A/KuEkm5FawfhWIfNqG+qfelVVR+V00g==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", + "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", "dev": true, "requires": { "ajv": "^7.0.2", @@ -3415,9 +3415,9 @@ "dev": true }, "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" diff --git a/web/package.json b/web/package.json index 2864f8e4f..e5c3b6548 100644 --- a/web/package.json +++ b/web/package.json @@ -19,7 +19,7 @@ "flowchart.js": "^1.15.0", "lit-element": "^2.4.0", "lit-html": "^1.3.0", - "rollup": "^2.36.1", + "rollup": "^2.36.2", "rollup-plugin-copy": "^3.3.0", "rollup-plugin-cssimport": "^1.0.2", "rollup-plugin-external-globals": "^0.6.1", @@ -29,7 +29,7 @@ "@rollup/plugin-typescript": "^8.1.0", "@typescript-eslint/eslint-plugin": "^4.13.0", "@typescript-eslint/parser": "^4.13.0", - "eslint": "^7.17.0", + "eslint": "^7.18.0", "eslint-config-google": "^0.14.0", "eslint-plugin-lit": "^1.3.0", "rollup-plugin-commonjs": "^10.1.0", diff --git a/website/docs/releases/2021.1.1.md b/website/docs/releases/2021.1.1.md index 4c4087cfa..db7a3141a 100644 --- a/website/docs/releases/2021.1.1.md +++ b/website/docs/releases/2021.1.1.md @@ -33,7 +33,7 @@ This release does not introduce any new requirements. ### docker-compose -Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-2021.1.1/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`. +Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-2021.1/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`. ### Kubernetes