django-database-task 0.2.2__tar.gz → 0.2.3__tar.gz

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.
Files changed (37) hide show
  1. {django_database_task-0.2.2/django_database_task.egg-info → django_database_task-0.2.3}/PKG-INFO +36 -2
  2. {django_database_task-0.2.2 → django_database_task-0.2.3}/README.md +35 -1
  3. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/__init__.py +1 -1
  4. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/backends.py +28 -6
  5. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/cloudtasks/auth.py +28 -1
  6. {django_database_task-0.2.2 → django_database_task-0.2.3/django_database_task.egg-info}/PKG-INFO +36 -2
  7. {django_database_task-0.2.2 → django_database_task-0.2.3}/pyproject.toml +1 -1
  8. {django_database_task-0.2.2 → django_database_task-0.2.3}/LICENSE +0 -0
  9. {django_database_task-0.2.2 → django_database_task-0.2.3}/MANIFEST.in +0 -0
  10. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/admin.py +0 -0
  11. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/apps.py +0 -0
  12. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/cloudtasks/__init__.py +0 -0
  13. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/cloudtasks/backend.py +0 -0
  14. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/cloudtasks/detection.py +0 -0
  15. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/executor.py +0 -0
  16. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/locale/ja/LC_MESSAGES/django.mo +0 -0
  17. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/locale/ja/LC_MESSAGES/django.po +0 -0
  18. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/management/__init__.py +0 -0
  19. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/management/commands/__init__.py +0 -0
  20. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/management/commands/purge_completed_database_tasks.py +0 -0
  21. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/management/commands/run_database_tasks.py +0 -0
  22. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/migrations/0001_initial.py +0 -0
  23. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/migrations/__init__.py +0 -0
  24. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/models.py +0 -0
  25. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/urls.py +0 -0
  26. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task/views.py +0 -0
  27. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task.egg-info/SOURCES.txt +0 -0
  28. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task.egg-info/dependency_links.txt +0 -0
  29. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task.egg-info/requires.txt +0 -0
  30. {django_database_task-0.2.2 → django_database_task-0.2.3}/django_database_task.egg-info/top_level.txt +0 -0
  31. {django_database_task-0.2.2 → django_database_task-0.2.3}/setup.cfg +0 -0
  32. {django_database_task-0.2.2 → django_database_task-0.2.3}/tests/test_admin.py +0 -0
  33. {django_database_task-0.2.2 → django_database_task-0.2.3}/tests/test_backend.py +0 -0
  34. {django_database_task-0.2.2 → django_database_task-0.2.3}/tests/test_commands.py +0 -0
  35. {django_database_task-0.2.2 → django_database_task-0.2.3}/tests/test_executor.py +0 -0
  36. {django_database_task-0.2.2 → django_database_task-0.2.3}/tests/test_models.py +0 -0
  37. {django_database_task-0.2.2 → django_database_task-0.2.3}/tests/test_views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-database-task
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: A database-backed task queue backend for Django 6.0's built-in task framework
5
5
  Author-email: Shinya Okano <tokibito@gmail.com>
6
6
  Maintainer-email: Shinya Okano <tokibito@gmail.com>
@@ -717,6 +717,40 @@ TASKS = {
717
717
 
718
718
  When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC tokens with each request. The backend automatically verifies these tokens on the `/tasks/execute/` and `/tasks/purge/` endpoints.
719
719
 
720
+ #### Required IAM Roles
721
+
722
+ To use OIDC authentication, the following IAM roles are required:
723
+
724
+ | Role | Description |
725
+ |------|-------------|
726
+ | `roles/cloudtasks.enqueuer` | Required to create tasks in Cloud Tasks queues |
727
+ | `roles/iam.serviceAccountUser` | Required to specify the OIDC service account when creating tasks |
728
+
729
+ **Setup:**
730
+
731
+ 1. Create a service account for OIDC token generation:
732
+ ```bash
733
+ gcloud iam service-accounts create cloud-tasks-invoker \
734
+ --display-name="Cloud Tasks Invoker"
735
+ ```
736
+
737
+ 2. Grant the Cloud Tasks Enqueuer role to the service account running your application (e.g., App Engine default service account):
738
+ ```bash
739
+ gcloud projects add-iam-policy-binding PROJECT_ID \
740
+ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \
741
+ --role="roles/cloudtasks.enqueuer"
742
+ ```
743
+
744
+ 3. Grant the Service Account User role to allow impersonation of the OIDC service account:
745
+ ```bash
746
+ gcloud iam service-accounts add-iam-policy-binding \
747
+ cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com \
748
+ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \
749
+ --role="roles/iam.serviceAccountUser"
750
+ ```
751
+
752
+ **Note:** The OIDC service account specified in `OIDC_SERVICE_ACCOUNT_EMAIL` does not need any additional roles. It is only used to generate the OIDC token that is included in the HTTP request to your task handler.
753
+
720
754
  ```python
721
755
  # settings.py - Automatic OIDC verification
722
756
  TASKS = {
@@ -724,7 +758,7 @@ TASKS = {
724
758
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
725
759
  "QUEUES": [], # Allow all queue names
726
760
  "OPTIONS": {
727
- "OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
761
+ "OIDC_SERVICE_ACCOUNT_EMAIL": "cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com",
728
762
  # OIDC_AUDIENCE is auto-detected from handler URL if not set
729
763
  },
730
764
  },
@@ -681,6 +681,40 @@ TASKS = {
681
681
 
682
682
  When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC tokens with each request. The backend automatically verifies these tokens on the `/tasks/execute/` and `/tasks/purge/` endpoints.
683
683
 
684
+ #### Required IAM Roles
685
+
686
+ To use OIDC authentication, the following IAM roles are required:
687
+
688
+ | Role | Description |
689
+ |------|-------------|
690
+ | `roles/cloudtasks.enqueuer` | Required to create tasks in Cloud Tasks queues |
691
+ | `roles/iam.serviceAccountUser` | Required to specify the OIDC service account when creating tasks |
692
+
693
+ **Setup:**
694
+
695
+ 1. Create a service account for OIDC token generation:
696
+ ```bash
697
+ gcloud iam service-accounts create cloud-tasks-invoker \
698
+ --display-name="Cloud Tasks Invoker"
699
+ ```
700
+
701
+ 2. Grant the Cloud Tasks Enqueuer role to the service account running your application (e.g., App Engine default service account):
702
+ ```bash
703
+ gcloud projects add-iam-policy-binding PROJECT_ID \
704
+ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \
705
+ --role="roles/cloudtasks.enqueuer"
706
+ ```
707
+
708
+ 3. Grant the Service Account User role to allow impersonation of the OIDC service account:
709
+ ```bash
710
+ gcloud iam service-accounts add-iam-policy-binding \
711
+ cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com \
712
+ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \
713
+ --role="roles/iam.serviceAccountUser"
714
+ ```
715
+
716
+ **Note:** The OIDC service account specified in `OIDC_SERVICE_ACCOUNT_EMAIL` does not need any additional roles. It is only used to generate the OIDC token that is included in the HTTP request to your task handler.
717
+
684
718
  ```python
685
719
  # settings.py - Automatic OIDC verification
686
720
  TASKS = {
@@ -688,7 +722,7 @@ TASKS = {
688
722
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
689
723
  "QUEUES": [], # Allow all queue names
690
724
  "OPTIONS": {
691
- "OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
725
+ "OIDC_SERVICE_ACCOUNT_EMAIL": "cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com",
692
726
  # OIDC_AUDIENCE is auto-detected from handler URL if not set
693
727
  },
694
728
  },
@@ -2,7 +2,7 @@
2
2
  django-database-task: A database-backed task queue backend for Django 6.0's task framework.
3
3
  """
4
4
 
5
- __version__ = "0.2.2"
5
+ __version__ = "0.2.3"
6
6
 
7
7
 
8
8
  def __getattr__(name):
@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import logging
2
3
  import traceback
3
4
  from importlib import import_module
4
5
  from inspect import iscoroutinefunction
@@ -10,6 +11,8 @@ from django.tasks.signals import task_enqueued, task_finished, task_started
10
11
  from django.utils import timezone
11
12
  from django.utils.json import normalize_json
12
13
 
14
+ logger = logging.getLogger("django_database_task")
15
+
13
16
 
14
17
  class DatabaseTaskBackend(BaseTaskBackend):
15
18
  """A task backend that persists tasks in the database."""
@@ -200,6 +203,20 @@ class DatabaseTaskBackend(BaseTaskBackend):
200
203
  ]
201
204
  )
202
205
 
206
+ # Send signal for success
207
+ db_task.refresh_from_db()
208
+ final_result = self._db_task_to_result(db_task, task)
209
+ # Note: Django's task_finished handler logs "NoneType: None" after this
210
+ # due to exc_info=sys.exc_info() being called outside exception context.
211
+ # This is a known Django issue and will be fixed upstream.
212
+ logger.info(
213
+ "Task completed successfully: id=%s path=%s",
214
+ final_result.id,
215
+ db_task.task_path,
216
+ )
217
+ task_finished.send(sender=self.__class__, task_result=final_result)
218
+ return final_result
219
+
203
220
  except Exception as e:
204
221
  # Failure
205
222
  error = TaskError(
@@ -221,9 +238,14 @@ class DatabaseTaskBackend(BaseTaskBackend):
221
238
  update_fields=["status", "errors_json", "finished_at", "updated_at"]
222
239
  )
223
240
 
224
- # Get final result and send signal
225
- db_task.refresh_from_db()
226
- final_result = self._db_task_to_result(db_task, task)
227
- task_finished.send(sender=self.__class__, task_result=final_result)
228
-
229
- return final_result
241
+ # Send signal for failure (with exception context for Django's logging)
242
+ db_task.refresh_from_db()
243
+ final_result = self._db_task_to_result(db_task, task)
244
+ logger.error(
245
+ "Task failed: id=%s path=%s error=%s",
246
+ final_result.id,
247
+ db_task.task_path,
248
+ error.exception_class_path,
249
+ )
250
+ task_finished.send(sender=self.__class__, task_result=final_result)
251
+ return final_result
@@ -5,12 +5,16 @@ Provides authentication handler and decorator for verifying OIDC tokens
5
5
  sent by Cloud Tasks.
6
6
  """
7
7
 
8
+ import logging
9
+ import traceback
8
10
  from functools import wraps
9
11
 
10
12
  from django.http import JsonResponse
11
13
  from google.auth.transport import requests as google_requests
12
14
  from google.oauth2 import id_token
13
15
 
16
+ logger = logging.getLogger("django_database_task.cloudtasks.auth")
17
+
14
18
 
15
19
  def create_oidc_auth_handler(audience):
16
20
  """
@@ -64,8 +68,31 @@ def create_oidc_auth_handler(audience):
64
68
  # Attach claims to request for use in view
65
69
  request.cloud_tasks_claims = claims
66
70
 
71
+ # Log successful verification
72
+ service_account = claims.get("email", "unknown")
73
+ logger.info(
74
+ "OIDC token verified successfully: service_account=%s audience=%s",
75
+ service_account,
76
+ audience,
77
+ )
78
+
67
79
  except Exception as e:
68
- return JsonResponse({"error": f"Invalid token: {e}"}, status=401)
80
+ # Log the full exception for debugging
81
+ # Use print as fallback since logging config may not capture this logger
82
+ error_type = type(e).__name__
83
+ error_msg = str(e) if str(e) else "No details available"
84
+ tb = traceback.format_exc()
85
+ full_error = (
86
+ f"OIDC token verification failed: {error_type}: {error_msg}\n{tb}"
87
+ )
88
+ logger.error(full_error)
89
+ # Also print to stderr for environments where logging is not configured
90
+ import sys
91
+
92
+ print(full_error, file=sys.stderr)
93
+ return JsonResponse(
94
+ {"error": f"Invalid token: {error_type}: {error_msg}"}, status=401
95
+ )
69
96
 
70
97
  return None
71
98
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-database-task
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: A database-backed task queue backend for Django 6.0's built-in task framework
5
5
  Author-email: Shinya Okano <tokibito@gmail.com>
6
6
  Maintainer-email: Shinya Okano <tokibito@gmail.com>
@@ -717,6 +717,40 @@ TASKS = {
717
717
 
718
718
  When `OIDC_SERVICE_ACCOUNT_EMAIL` is configured, Cloud Tasks will send OIDC tokens with each request. The backend automatically verifies these tokens on the `/tasks/execute/` and `/tasks/purge/` endpoints.
719
719
 
720
+ #### Required IAM Roles
721
+
722
+ To use OIDC authentication, the following IAM roles are required:
723
+
724
+ | Role | Description |
725
+ |------|-------------|
726
+ | `roles/cloudtasks.enqueuer` | Required to create tasks in Cloud Tasks queues |
727
+ | `roles/iam.serviceAccountUser` | Required to specify the OIDC service account when creating tasks |
728
+
729
+ **Setup:**
730
+
731
+ 1. Create a service account for OIDC token generation:
732
+ ```bash
733
+ gcloud iam service-accounts create cloud-tasks-invoker \
734
+ --display-name="Cloud Tasks Invoker"
735
+ ```
736
+
737
+ 2. Grant the Cloud Tasks Enqueuer role to the service account running your application (e.g., App Engine default service account):
738
+ ```bash
739
+ gcloud projects add-iam-policy-binding PROJECT_ID \
740
+ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \
741
+ --role="roles/cloudtasks.enqueuer"
742
+ ```
743
+
744
+ 3. Grant the Service Account User role to allow impersonation of the OIDC service account:
745
+ ```bash
746
+ gcloud iam service-accounts add-iam-policy-binding \
747
+ cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com \
748
+ --member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \
749
+ --role="roles/iam.serviceAccountUser"
750
+ ```
751
+
752
+ **Note:** The OIDC service account specified in `OIDC_SERVICE_ACCOUNT_EMAIL` does not need any additional roles. It is only used to generate the OIDC token that is included in the HTTP request to your task handler.
753
+
720
754
  ```python
721
755
  # settings.py - Automatic OIDC verification
722
756
  TASKS = {
@@ -724,7 +758,7 @@ TASKS = {
724
758
  "BACKEND": "django_database_task.cloudtasks.CloudTasksDatabaseBackend",
725
759
  "QUEUES": [], # Allow all queue names
726
760
  "OPTIONS": {
727
- "OIDC_SERVICE_ACCOUNT_EMAIL": "my-sa@project.iam.gserviceaccount.com",
761
+ "OIDC_SERVICE_ACCOUNT_EMAIL": "cloud-tasks-invoker@PROJECT_ID.iam.gserviceaccount.com",
728
762
  # OIDC_AUDIENCE is auto-detected from handler URL if not set
729
763
  },
730
764
  },
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "django-database-task"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "A database-backed task queue backend for Django 6.0's built-in task framework"
9
9
  readme = "README.md"
10
10
  license = "MIT"