taskqueue-toolkit 0.1.0__tar.gz → 0.1.1__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 (28) hide show
  1. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/PKG-INFO +9 -1
  2. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/README.md +8 -0
  3. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/pyproject.toml +1 -1
  4. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/pyproject.toml.orig +1 -1
  5. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/sns.py +6 -3
  6. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/sqs.py +5 -3
  7. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/task_queue.py +6 -0
  8. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/LICENSE +0 -0
  9. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/__init__.py +0 -0
  10. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/outbox/__init__.py +0 -0
  11. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/outbox/orm.py +0 -0
  12. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/outbox/relay.py +0 -0
  13. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/outbox/repository.py +0 -0
  14. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/py.typed +0 -0
  15. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/__init__.py +0 -0
  16. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/aws_session.py +0 -0
  17. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/dsn.py +0 -0
  18. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/factory.py +0 -0
  19. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/pubsub.py +0 -0
  20. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/rabbitmq.py +0 -0
  21. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/redis_streams.py +0 -0
  22. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/queue/registry.py +0 -0
  23. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/testing/__init__.py +0 -0
  24. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/testing/pubsub.py +0 -0
  25. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/testing/rabbitmq.py +0 -0
  26. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/testing/redis_streams.py +0 -0
  27. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/testing/sns.py +0 -0
  28. {taskqueue_toolkit-0.1.0 → taskqueue_toolkit-0.1.1}/src/taskqueue_toolkit/testing/sqs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: taskqueue-toolkit
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Broker-agnostic async task queue (RabbitMQ, SQS, SNS, Redis Streams, Pub/Sub) with a Postgres outbox pattern
5
5
  Author: Walid Boughdiri
6
6
  Author-email: Walid Boughdiri <walid.boughdiri@gmail.com>
@@ -152,6 +152,12 @@ Each adapter constructor takes an injectable client/connection factory for exact
152
152
 
153
153
  Create one broker instance per test — each owns its own isolated in-memory state, so there's nothing to reset between tests and no risk of one test's queue leaking into another's.
154
154
 
155
+ ## Security
156
+
157
+ `Decoder[T]` runs on bytes received from a broker — in most deployments, a source outside this process's control. Using an unsafe deserializer (`pickle.loads`, `yaml.load` without `SafeLoader`, `eval`, ...) as your `decode` callback means whoever can publish to your queue/topic can run arbitrary code in your consumer. Use a safe format (JSON, msgpack, protobuf, ...) unless every publisher is fully trusted.
158
+
159
+ This package's own code is checked on every push/PR and before every release via [bandit](https://bandit.readthedocs.io/) (unsafe code patterns) and [pip-audit](https://github.com/pypa/pip-audit) (known CVEs in resolved dependencies), alongside ruff, mypy, and the test suite. Found a vulnerability? Please open an issue.
160
+
155
161
  ## Development
156
162
 
157
163
  ```bash
@@ -160,4 +166,6 @@ uv run pytest
160
166
  uv run ruff check .
161
167
  uv run ruff format .
162
168
  uv run mypy .
169
+ uvx bandit -r src/
170
+ uvx pip-audit --path .venv
163
171
  ```
@@ -117,6 +117,12 @@ Each adapter constructor takes an injectable client/connection factory for exact
117
117
 
118
118
  Create one broker instance per test — each owns its own isolated in-memory state, so there's nothing to reset between tests and no risk of one test's queue leaking into another's.
119
119
 
120
+ ## Security
121
+
122
+ `Decoder[T]` runs on bytes received from a broker — in most deployments, a source outside this process's control. Using an unsafe deserializer (`pickle.loads`, `yaml.load` without `SafeLoader`, `eval`, ...) as your `decode` callback means whoever can publish to your queue/topic can run arbitrary code in your consumer. Use a safe format (JSON, msgpack, protobuf, ...) unless every publisher is fully trusted.
123
+
124
+ This package's own code is checked on every push/PR and before every release via [bandit](https://bandit.readthedocs.io/) (unsafe code patterns) and [pip-audit](https://github.com/pypa/pip-audit) (known CVEs in resolved dependencies), alongside ruff, mypy, and the test suite. Found a vulnerability? Please open an issue.
125
+
120
126
  ## Development
121
127
 
122
128
  ```bash
@@ -125,4 +131,6 @@ uv run pytest
125
131
  uv run ruff check .
126
132
  uv run ruff format .
127
133
  uv run mypy .
134
+ uvx bandit -r src/
135
+ uvx pip-audit --path .venv
128
136
  ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "taskqueue-toolkit"
3
- version = "0.1.0"
3
+ version = "0.1.1"
4
4
  description = "Broker-agnostic async task queue (RabbitMQ, SQS, SNS, Redis Streams, Pub/Sub) with a Postgres outbox pattern"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "taskqueue-toolkit"
3
- version = "0.1.0"
3
+ version = "0.1.1"
4
4
  description = "Broker-agnostic async task queue (RabbitMQ, SQS, SNS, Redis Streams, Pub/Sub) with a Postgres outbox pattern"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -6,10 +6,13 @@ import logging
6
6
  from collections.abc import AsyncIterator, Callable
7
7
  from contextlib import AbstractAsyncContextManager, asynccontextmanager
8
8
  from dataclasses import dataclass, field
9
+ from typing import TYPE_CHECKING
9
10
 
10
11
  import aioboto3
11
- from types_aiobotocore_sns.client import SNSClient
12
- from types_aiobotocore_sqs.client import SQSClient
12
+
13
+ if TYPE_CHECKING:
14
+ from types_aiobotocore_sns.client import SNSClient
15
+ from types_aiobotocore_sqs.client import SQSClient
13
16
 
14
17
  from taskqueue_toolkit.queue.aws_session import aws_session_kwargs
15
18
  from taskqueue_toolkit.queue.dsn import SnsDsn
@@ -20,7 +23,7 @@ logger = logging.getLogger(__name__)
20
23
  _LONG_POLL_WAIT_SECONDS = 10
21
24
  _SUBSCRIBER_QUEUE_SUFFIX = "-subscriber"
22
25
 
23
- ClientFactory = Callable[[SnsDsn], AbstractAsyncContextManager[tuple[SNSClient, SQSClient]]]
26
+ ClientFactory = Callable[[SnsDsn], AbstractAsyncContextManager["tuple[SNSClient, SQSClient]"]]
24
27
 
25
28
 
26
29
  @asynccontextmanager
@@ -5,10 +5,12 @@ import logging
5
5
  from collections.abc import AsyncIterator, Callable
6
6
  from contextlib import AbstractAsyncContextManager
7
7
  from dataclasses import dataclass, field
8
- from typing import cast
8
+ from typing import TYPE_CHECKING, cast
9
9
 
10
10
  import aioboto3
11
- from types_aiobotocore_sqs.client import SQSClient
11
+
12
+ if TYPE_CHECKING:
13
+ from types_aiobotocore_sqs.client import SQSClient
12
14
 
13
15
  from taskqueue_toolkit.queue.aws_session import aws_session_kwargs
14
16
  from taskqueue_toolkit.queue.dsn import SqsDsn
@@ -18,7 +20,7 @@ logger = logging.getLogger(__name__)
18
20
 
19
21
  _LONG_POLL_WAIT_SECONDS = 10
20
22
 
21
- ClientFactory = Callable[[SqsDsn], AbstractAsyncContextManager[SQSClient]]
23
+ ClientFactory = Callable[[SqsDsn], AbstractAsyncContextManager["SQSClient"]]
22
24
 
23
25
 
24
26
  def _default_client_factory(dsn: SqsDsn) -> AbstractAsyncContextManager[SQSClient]:
@@ -7,6 +7,12 @@ T = TypeVar("T")
7
7
  T_co = TypeVar("T_co", covariant=True)
8
8
 
9
9
  Encoder = Callable[[T], bytes]
10
+ # SECURITY: Decoder runs on bytes received from a broker — a source outside
11
+ # this process's control in most deployments. Using an unsafe deserializer
12
+ # here (pickle.loads, yaml.load without SafeLoader, eval, ...) turns
13
+ # whoever can publish to your queue/topic into someone who can run
14
+ # arbitrary code in your consumer. Prefer a safe format (json, msgpack,
15
+ # protobuf) unless every publisher is fully trusted.
10
16
  Decoder = Callable[[bytes], T]
11
17
 
12
18