stemtrace 0.3.5__tar.gz → 0.3.6__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.
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.bumpversion.toml +1 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.github/dependabot.yml +10 -1
- stemtrace-0.3.6/.github/workflows/ci.yml +230 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.github/workflows/e2e.yml +26 -18
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.github/workflows/release.yml +27 -20
- {stemtrace-0.3.5 → stemtrace-0.3.6}/CHANGELOG.md +32 -1
- stemtrace-0.3.6/Dockerfile +69 -0
- stemtrace-0.3.6/Dockerfile.e2e +37 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/PKG-INFO +28 -5
- {stemtrace-0.3.5 → stemtrace-0.3.6}/README.md +23 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/build_ui.py +44 -3
- stemtrace-0.3.6/docs/brand/stemtrace-mark-light.svg +1 -0
- stemtrace-0.3.6/docs/brand/stemtrace-mark.svg +1 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/examples/fastapi_integration.py +1 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/examples/with_auth.py +1 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/examples/with_login.py +1 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/pyproject.toml +7 -4
- stemtrace-0.3.6/scripts/wait_for_http.py +77 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/__init__.py +1 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/core/ports.py +21 -1
- stemtrace-0.3.6/src/stemtrace/library/transports/redis.py +381 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/api/routes.py +19 -3
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/api/schemas.py +6 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/consumer.py +109 -12
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/biome.json +1 -1
- stemtrace-0.3.6/src/stemtrace/server/ui/frontend/index.html +19 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/package-lock.json +679 -1227
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/package.json +12 -6
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/api/client.ts +1 -0
- stemtrace-0.3.6/src/stemtrace/server/ui/frontend/src/components/SproutMark.tsx +42 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/TimelineBar.tsx +1 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/routes/__root.tsx +10 -4
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/static.py +10 -1
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/templates/login.html +4 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/conftest.py +2 -2
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/integration/test_fastapi_integration.py +30 -26
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/integration/test_rabbitmq_transport.py +3 -3
- stemtrace-0.3.6/tests/integration/test_redis_resilience_docker.py +205 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/integration/test_redis_transport.py +7 -7
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/integration/test_static_ui.py +52 -0
- stemtrace-0.3.6/tests/integration/test_wait_for_http_redirects.py +80 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/integration/test_workers_refresh.py +5 -3
- stemtrace-0.3.6/tests/unit/test_build_ui_hook.py +68 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_consumer.py +334 -13
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_events.py +21 -21
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_examples.py +12 -8
- stemtrace-0.3.6/tests/unit/test_favicon.py +48 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_form_login.py +26 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_graph.py +88 -88
- stemtrace-0.3.6/tests/unit/test_redis_resilience.py +424 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_routes.py +59 -6
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_store.py +10 -10
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_transports.py +48 -15
- stemtrace-0.3.6/tests/unit/test_wait_for_http_script.py +103 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_websocket.py +2 -2
- {stemtrace-0.3.5 → stemtrace-0.3.6}/uv.lock +123 -101
- stemtrace-0.3.5/.github/workflows/ci.yml +0 -189
- stemtrace-0.3.5/Dockerfile +0 -58
- stemtrace-0.3.5/Dockerfile.e2e +0 -27
- stemtrace-0.3.5/scripts/wait_for_http.py +0 -41
- stemtrace-0.3.5/src/stemtrace/library/transports/redis.py +0 -165
- stemtrace-0.3.5/src/stemtrace/server/ui/frontend/index.html +0 -16
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.dockerignore +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.gitignore +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.pre-commit-config.yaml +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/.python-version +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/CONTRIBUTING.md +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/LICENSE +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/Makefile +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/docker-compose.e2e.rabbitmq.yml +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/docker-compose.e2e.yml +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/docker-compose.rabbitmq.yml +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/docker-compose.yml +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/docs/screenshots/task_details.png +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/docs/screenshots/unregistered.png +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/docs/screenshots/workflow.png +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/examples/celery_app.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/progress.md +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/core/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/core/events.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/core/exceptions.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/core/graph.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/bootsteps.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/config.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/scrubbing.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/signals.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/transports/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/transports/memory.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/library/transports/rabbitmq.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/py.typed +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/__main__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/api/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/api/websocket.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/fastapi/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/fastapi/auth.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/fastapi/extension.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/fastapi/form_auth.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/fastapi/login_routes.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/fastapi/router.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/store.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/playwright.config.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/postcss.config.js +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/api/queries.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/DateRangePicker.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/Filters.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/TaskGraph.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/TaskList.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/TaskStateBadge.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/TaskTimeline.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/components/Tooltip.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/hooks/WebSocketContext.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/hooks/useInfiniteScroll.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/index.css +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/main.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/routes/graph.$rootId.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/routes/graphs.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/routes/index.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/routes/registry.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/routes/tasks.$taskId.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/routes/workers.tsx +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/utils/format.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/src/vite-env.d.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tests/fixtures/mock-api.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tests/fixtures/mock-data.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tests/graphs.spec.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tests/registry.spec.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tests/task-detail.spec.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tests/tasks.spec.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tests/workers.spec.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tsconfig.json +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/tsconfig.tsbuildinfo +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/ui/frontend/vite.config.ts +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/src/stemtrace/server/websocket.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/e2e/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/e2e/conftest.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/e2e/tasks.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/e2e/test_api_e2e.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/e2e/test_workers_e2e.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/integration/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/integration/test_embedded_static.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/__init__.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_auth.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_bootsteps.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_config.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_exceptions.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_form_auth.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_init.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_scrubbing.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_signals.py +0 -0
- {stemtrace-0.3.5 → stemtrace-0.3.6}/tests/unit/test_ui_static_prefix.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
version: 2
|
|
2
2
|
updates:
|
|
3
|
-
|
|
3
|
+
# Python dependencies: pyproject.toml + uv.lock (CI and images install from the lock)
|
|
4
|
+
- package-ecosystem: uv
|
|
4
5
|
directory: /
|
|
5
6
|
schedule:
|
|
6
7
|
interval: weekly
|
|
@@ -20,3 +21,11 @@ updates:
|
|
|
20
21
|
interval: weekly
|
|
21
22
|
commit-message:
|
|
22
23
|
prefix: "chore(deps)"
|
|
24
|
+
|
|
25
|
+
# Base images in Dockerfile and Dockerfile.e2e (tags pinned by digest)
|
|
26
|
+
- package-ecosystem: docker
|
|
27
|
+
directory: /
|
|
28
|
+
schedule:
|
|
29
|
+
interval: weekly
|
|
30
|
+
commit-message:
|
|
31
|
+
prefix: "chore(deps)"
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [main]
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
concurrency:
|
|
11
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
12
|
+
cancel-in-progress: true
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
lint:
|
|
16
|
+
if: github.event_name == 'pull_request'
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
env:
|
|
19
|
+
UV_PYTHON: "3.12"
|
|
20
|
+
STEMTRACE_SKIP_UI_BUILD: "1"
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
23
|
+
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.12"
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
31
|
+
with:
|
|
32
|
+
enable-cache: true
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --locked --no-build --all-extras
|
|
36
|
+
|
|
37
|
+
- name: Lint with ruff
|
|
38
|
+
run: uv run --locked --no-build ruff check src/ tests/
|
|
39
|
+
|
|
40
|
+
- name: Check formatting
|
|
41
|
+
run: uv run --locked --no-build ruff format --check src/ tests/
|
|
42
|
+
|
|
43
|
+
type-check:
|
|
44
|
+
if: github.event_name == 'pull_request'
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
env:
|
|
47
|
+
UV_PYTHON: "3.12"
|
|
48
|
+
STEMTRACE_SKIP_UI_BUILD: "1"
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
51
|
+
|
|
52
|
+
- name: Set up Python
|
|
53
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
54
|
+
with:
|
|
55
|
+
python-version: "3.12"
|
|
56
|
+
|
|
57
|
+
- name: Install uv
|
|
58
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
59
|
+
with:
|
|
60
|
+
enable-cache: true
|
|
61
|
+
|
|
62
|
+
- name: Install dependencies
|
|
63
|
+
run: uv sync --locked --no-build --all-extras
|
|
64
|
+
|
|
65
|
+
- name: Type check with mypy
|
|
66
|
+
run: uv run --locked --no-build mypy src/ --strict
|
|
67
|
+
|
|
68
|
+
test:
|
|
69
|
+
if: github.event_name == 'pull_request'
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
env:
|
|
72
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
73
|
+
STEMTRACE_SKIP_UI_BUILD: "1"
|
|
74
|
+
strategy:
|
|
75
|
+
matrix:
|
|
76
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
77
|
+
steps:
|
|
78
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
79
|
+
|
|
80
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
81
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
82
|
+
with:
|
|
83
|
+
python-version: ${{ matrix.python-version }}
|
|
84
|
+
|
|
85
|
+
- name: Install uv
|
|
86
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
87
|
+
with:
|
|
88
|
+
enable-cache: true
|
|
89
|
+
|
|
90
|
+
- name: Install dependencies
|
|
91
|
+
run: uv sync --locked --no-build --all-extras
|
|
92
|
+
|
|
93
|
+
- name: Run tests
|
|
94
|
+
run: uv run --locked --no-build pytest --cov=stemtrace --cov-branch --cov-report=xml --cov-fail-under=95
|
|
95
|
+
|
|
96
|
+
- name: Upload coverage
|
|
97
|
+
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
|
98
|
+
if: matrix.python-version == '3.12'
|
|
99
|
+
with:
|
|
100
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
101
|
+
files: ./coverage.xml
|
|
102
|
+
fail_ci_if_error: false
|
|
103
|
+
|
|
104
|
+
audit:
|
|
105
|
+
name: Audit runtime dependencies
|
|
106
|
+
runs-on: ubuntu-latest
|
|
107
|
+
env:
|
|
108
|
+
UV_PYTHON: "3.12"
|
|
109
|
+
steps:
|
|
110
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
111
|
+
|
|
112
|
+
- name: Set up Python
|
|
113
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
114
|
+
with:
|
|
115
|
+
python-version: "3.12"
|
|
116
|
+
|
|
117
|
+
- name: Install uv
|
|
118
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
119
|
+
with:
|
|
120
|
+
enable-cache: true
|
|
121
|
+
|
|
122
|
+
- name: Export locked runtime dependencies
|
|
123
|
+
run: uv export --frozen --no-emit-project --no-dev --output-file requirements-audit.txt
|
|
124
|
+
|
|
125
|
+
- name: Audit for known vulnerabilities
|
|
126
|
+
run: uvx --no-build pip-audit==2.10.1 --strict --require-hashes --disable-pip -r requirements-audit.txt
|
|
127
|
+
|
|
128
|
+
frontend:
|
|
129
|
+
if: github.event_name == 'pull_request'
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
defaults:
|
|
132
|
+
run:
|
|
133
|
+
working-directory: src/stemtrace/server/ui/frontend
|
|
134
|
+
steps:
|
|
135
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
136
|
+
|
|
137
|
+
- name: Set up Node.js
|
|
138
|
+
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
|
139
|
+
with:
|
|
140
|
+
node-version: "22"
|
|
141
|
+
cache: "npm"
|
|
142
|
+
cache-dependency-path: src/stemtrace/server/ui/frontend/package-lock.json
|
|
143
|
+
|
|
144
|
+
- name: Install dependencies
|
|
145
|
+
run: npm ci --ignore-scripts
|
|
146
|
+
|
|
147
|
+
- name: Lint with Biome
|
|
148
|
+
run: npm run check
|
|
149
|
+
|
|
150
|
+
- name: Type check with TypeScript
|
|
151
|
+
run: npm run typecheck
|
|
152
|
+
|
|
153
|
+
build:
|
|
154
|
+
if: github.event_name == 'pull_request'
|
|
155
|
+
runs-on: ubuntu-latest
|
|
156
|
+
env:
|
|
157
|
+
UV_PYTHON: "3.12"
|
|
158
|
+
needs: [lint, type-check, test, frontend]
|
|
159
|
+
steps:
|
|
160
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
161
|
+
|
|
162
|
+
- name: Set up Python
|
|
163
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
164
|
+
with:
|
|
165
|
+
python-version: "3.12"
|
|
166
|
+
|
|
167
|
+
- name: Install uv
|
|
168
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
169
|
+
with:
|
|
170
|
+
enable-cache: true
|
|
171
|
+
|
|
172
|
+
- name: Set up Node.js
|
|
173
|
+
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
|
174
|
+
with:
|
|
175
|
+
node-version: "22"
|
|
176
|
+
cache: "npm"
|
|
177
|
+
cache-dependency-path: src/stemtrace/server/ui/frontend/package-lock.json
|
|
178
|
+
|
|
179
|
+
- name: Install frontend dependencies
|
|
180
|
+
run: npm ci --ignore-scripts
|
|
181
|
+
working-directory: src/stemtrace/server/ui/frontend
|
|
182
|
+
|
|
183
|
+
- name: Install build tools
|
|
184
|
+
run: uv sync --locked --no-build --all-extras --no-install-project
|
|
185
|
+
|
|
186
|
+
- name: Build package
|
|
187
|
+
run: uv run --locked --no-build --no-sync pyproject-build --no-isolation
|
|
188
|
+
|
|
189
|
+
- name: Verify package
|
|
190
|
+
run: uv run --locked --no-build --no-sync twine check dist/*
|
|
191
|
+
|
|
192
|
+
- name: Upload dist artifacts
|
|
193
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
194
|
+
with:
|
|
195
|
+
name: dist
|
|
196
|
+
path: dist/
|
|
197
|
+
|
|
198
|
+
coverage-main:
|
|
199
|
+
# Keep PR checks as the main gate, but ensure Codecov gets updated for the
|
|
200
|
+
# actual default-branch commit after merges (or direct pushes / releases).
|
|
201
|
+
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
|
|
202
|
+
runs-on: ubuntu-latest
|
|
203
|
+
env:
|
|
204
|
+
UV_PYTHON: "3.12"
|
|
205
|
+
STEMTRACE_SKIP_UI_BUILD: "1"
|
|
206
|
+
steps:
|
|
207
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
208
|
+
|
|
209
|
+
- name: Set up Python
|
|
210
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
211
|
+
with:
|
|
212
|
+
python-version: "3.12"
|
|
213
|
+
|
|
214
|
+
- name: Install uv
|
|
215
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
216
|
+
with:
|
|
217
|
+
enable-cache: true
|
|
218
|
+
|
|
219
|
+
- name: Install dependencies
|
|
220
|
+
run: uv sync --locked --no-build --all-extras
|
|
221
|
+
|
|
222
|
+
- name: Run tests (coverage only)
|
|
223
|
+
run: uv run --locked --no-build pytest --cov=stemtrace --cov-branch --cov-report=xml --cov-fail-under=95
|
|
224
|
+
|
|
225
|
+
- name: Upload coverage (main)
|
|
226
|
+
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
|
|
227
|
+
with:
|
|
228
|
+
token: ${{ secrets.CODECOV_TOKEN }}
|
|
229
|
+
files: ./coverage.xml
|
|
230
|
+
fail_ci_if_error: false
|
|
@@ -12,6 +12,10 @@ jobs:
|
|
|
12
12
|
api-e2e:
|
|
13
13
|
name: API E2E Tests
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
|
+
env:
|
|
16
|
+
UV_PYTHON: "3.12"
|
|
17
|
+
# The Docker images build their own UI; skip the host-side build.
|
|
18
|
+
STEMTRACE_SKIP_UI_BUILD: "1"
|
|
15
19
|
timeout-minutes: 15
|
|
16
20
|
strategy:
|
|
17
21
|
fail-fast: false
|
|
@@ -21,10 +25,10 @@ jobs:
|
|
|
21
25
|
- rabbitmq
|
|
22
26
|
|
|
23
27
|
steps:
|
|
24
|
-
- uses: actions/checkout@v6
|
|
28
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
25
29
|
|
|
26
30
|
- name: Set up Docker Buildx
|
|
27
|
-
uses: docker/setup-buildx-action@v4
|
|
31
|
+
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
|
28
32
|
|
|
29
33
|
- name: Select compose file and Celery env
|
|
30
34
|
run: |
|
|
@@ -51,20 +55,20 @@ jobs:
|
|
|
51
55
|
echo "Services ready!"
|
|
52
56
|
|
|
53
57
|
- name: Set up Python
|
|
54
|
-
uses: actions/setup-python@v6
|
|
58
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
55
59
|
with:
|
|
56
60
|
python-version: "3.12"
|
|
57
61
|
|
|
58
62
|
- name: Install uv
|
|
59
|
-
uses: astral-sh/setup-uv@v7
|
|
63
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
60
64
|
with:
|
|
61
65
|
enable-cache: true
|
|
62
66
|
|
|
63
67
|
- name: Install dependencies
|
|
64
|
-
run: uv sync --all-extras
|
|
68
|
+
run: uv sync --locked --no-build --all-extras
|
|
65
69
|
|
|
66
70
|
- name: Run API E2E tests
|
|
67
|
-
run: uv run pytest tests/e2e/ -m e2e -v --tb=short
|
|
71
|
+
run: uv run --locked --no-build pytest tests/e2e/ -m e2e -v --tb=short
|
|
68
72
|
|
|
69
73
|
- name: Show logs on failure
|
|
70
74
|
if: failure()
|
|
@@ -79,6 +83,10 @@ jobs:
|
|
|
79
83
|
playwright:
|
|
80
84
|
name: Playwright E2E Tests
|
|
81
85
|
runs-on: ubuntu-latest
|
|
86
|
+
env:
|
|
87
|
+
UV_PYTHON: "3.12"
|
|
88
|
+
# The Docker images build their own UI; skip the host-side build.
|
|
89
|
+
STEMTRACE_SKIP_UI_BUILD: "1"
|
|
82
90
|
timeout-minutes: 20
|
|
83
91
|
strategy:
|
|
84
92
|
fail-fast: false
|
|
@@ -88,10 +96,10 @@ jobs:
|
|
|
88
96
|
- rabbitmq
|
|
89
97
|
|
|
90
98
|
steps:
|
|
91
|
-
- uses: actions/checkout@v6
|
|
99
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
92
100
|
|
|
93
101
|
- name: Set up Docker Buildx
|
|
94
|
-
uses: docker/setup-buildx-action@v4
|
|
102
|
+
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
|
95
103
|
|
|
96
104
|
- name: Select compose file and Celery env
|
|
97
105
|
run: |
|
|
@@ -117,22 +125,22 @@ jobs:
|
|
|
117
125
|
echo "Services ready!"
|
|
118
126
|
|
|
119
127
|
- name: Set up Python
|
|
120
|
-
uses: actions/setup-python@v6
|
|
128
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
121
129
|
with:
|
|
122
130
|
python-version: "3.12"
|
|
123
131
|
|
|
124
132
|
- name: Install uv
|
|
125
|
-
uses: astral-sh/setup-uv@v7
|
|
133
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
126
134
|
with:
|
|
127
135
|
enable-cache: true
|
|
128
136
|
|
|
129
137
|
- name: Install Python dependencies
|
|
130
|
-
run: uv sync --all-extras
|
|
138
|
+
run: uv sync --locked --no-build --all-extras
|
|
131
139
|
|
|
132
140
|
- name: Submit test tasks
|
|
133
141
|
run: |
|
|
134
142
|
# Submit some tasks to populate the UI for testing
|
|
135
|
-
uv run python -c "
|
|
143
|
+
uv run --locked --no-build python -c "
|
|
136
144
|
from tests.e2e.tasks import add, create_workflow, always_fails
|
|
137
145
|
# Submit a few tasks
|
|
138
146
|
add.delay(1, 2)
|
|
@@ -145,19 +153,19 @@ jobs:
|
|
|
145
153
|
sleep 5
|
|
146
154
|
|
|
147
155
|
- name: Set up Node.js
|
|
148
|
-
uses: actions/setup-node@v6
|
|
156
|
+
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
|
149
157
|
with:
|
|
150
|
-
node-version: "
|
|
158
|
+
node-version: "22"
|
|
151
159
|
cache: "npm"
|
|
152
160
|
cache-dependency-path: src/stemtrace/server/ui/frontend/package-lock.json
|
|
153
161
|
|
|
154
162
|
- name: Install frontend dependencies
|
|
155
163
|
working-directory: src/stemtrace/server/ui/frontend
|
|
156
|
-
run: npm ci
|
|
164
|
+
run: npm ci --ignore-scripts
|
|
157
165
|
|
|
158
166
|
- name: Install Playwright browsers
|
|
159
167
|
working-directory: src/stemtrace/server/ui/frontend
|
|
160
|
-
run:
|
|
168
|
+
run: ./node_modules/.bin/playwright install chromium --with-deps
|
|
161
169
|
|
|
162
170
|
- name: Run Playwright tests
|
|
163
171
|
working-directory: src/stemtrace/server/ui/frontend
|
|
@@ -167,7 +175,7 @@ jobs:
|
|
|
167
175
|
PLAYWRIGHT_BASE_URL: http://localhost:8000
|
|
168
176
|
|
|
169
177
|
- name: Upload Playwright report
|
|
170
|
-
uses: actions/upload-artifact@v7
|
|
178
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
171
179
|
if: always()
|
|
172
180
|
with:
|
|
173
181
|
name: playwright-report-${{ matrix.broker }}
|
|
@@ -175,7 +183,7 @@ jobs:
|
|
|
175
183
|
retention-days: 7
|
|
176
184
|
|
|
177
185
|
- name: Upload test results
|
|
178
|
-
uses: actions/upload-artifact@v7
|
|
186
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
179
187
|
if: failure()
|
|
180
188
|
with:
|
|
181
189
|
name: playwright-test-results-${{ matrix.broker }}
|
|
@@ -18,11 +18,13 @@ env:
|
|
|
18
18
|
jobs:
|
|
19
19
|
build:
|
|
20
20
|
runs-on: ubuntu-latest
|
|
21
|
+
env:
|
|
22
|
+
UV_PYTHON: "3.12"
|
|
21
23
|
outputs:
|
|
22
24
|
version: ${{ steps.version.outputs.version }}
|
|
23
25
|
tag: ${{ steps.version.outputs.tag }}
|
|
24
26
|
steps:
|
|
25
|
-
- uses: actions/checkout@v6
|
|
27
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
26
28
|
|
|
27
29
|
- name: Determine version
|
|
28
30
|
id: version
|
|
@@ -49,32 +51,37 @@ jobs:
|
|
|
49
51
|
echo "✅ Version $PYPROJECT_VERSION matches"
|
|
50
52
|
|
|
51
53
|
- name: Set up Python
|
|
52
|
-
uses: actions/setup-python@v6
|
|
54
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
53
55
|
with:
|
|
54
56
|
python-version: "3.12"
|
|
55
57
|
|
|
56
58
|
- name: Set up Node.js
|
|
57
|
-
uses: actions/setup-node@v6
|
|
59
|
+
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
|
|
58
60
|
with:
|
|
59
|
-
node-version: "
|
|
61
|
+
node-version: "22"
|
|
60
62
|
cache: "npm"
|
|
61
63
|
cache-dependency-path: src/stemtrace/server/ui/frontend/package-lock.json
|
|
62
64
|
|
|
65
|
+
- name: Install uv
|
|
66
|
+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
|
67
|
+
with:
|
|
68
|
+
enable-cache: false
|
|
69
|
+
|
|
63
70
|
- name: Install frontend dependencies
|
|
64
|
-
run: npm ci
|
|
71
|
+
run: npm ci --ignore-scripts
|
|
65
72
|
working-directory: src/stemtrace/server/ui/frontend
|
|
66
73
|
|
|
67
74
|
- name: Install build tools
|
|
68
|
-
run:
|
|
75
|
+
run: uv sync --locked --no-build --all-extras --no-install-project
|
|
69
76
|
|
|
70
77
|
- name: Build package
|
|
71
|
-
run:
|
|
78
|
+
run: uv run --locked --no-build --no-sync pyproject-build --no-isolation
|
|
72
79
|
|
|
73
80
|
- name: Verify package
|
|
74
|
-
run: twine check dist/*
|
|
81
|
+
run: uv run --locked --no-build --no-sync twine check dist/*
|
|
75
82
|
|
|
76
83
|
- name: Upload dist artifacts
|
|
77
|
-
uses: actions/upload-artifact@v7
|
|
84
|
+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
|
78
85
|
with:
|
|
79
86
|
name: dist
|
|
80
87
|
path: dist/
|
|
@@ -87,13 +94,13 @@ jobs:
|
|
|
87
94
|
id-token: write
|
|
88
95
|
steps:
|
|
89
96
|
- name: Download dist artifacts
|
|
90
|
-
uses: actions/download-artifact@v8
|
|
97
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
91
98
|
with:
|
|
92
99
|
name: dist
|
|
93
100
|
path: dist/
|
|
94
101
|
|
|
95
102
|
- name: Publish to PyPI
|
|
96
|
-
uses: pypa/gh-action-pypi-publish@
|
|
103
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
97
104
|
|
|
98
105
|
docker:
|
|
99
106
|
needs: build
|
|
@@ -102,16 +109,16 @@ jobs:
|
|
|
102
109
|
contents: read
|
|
103
110
|
packages: write
|
|
104
111
|
steps:
|
|
105
|
-
- uses: actions/checkout@v6
|
|
112
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
106
113
|
|
|
107
114
|
- name: Set up QEMU
|
|
108
|
-
uses: docker/setup-qemu-action@
|
|
115
|
+
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
|
|
109
116
|
|
|
110
117
|
- name: Set up Docker Buildx
|
|
111
|
-
uses: docker/setup-buildx-action@v4
|
|
118
|
+
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
|
|
112
119
|
|
|
113
120
|
- name: Log in to GitHub Container Registry
|
|
114
|
-
uses: docker/login-action@
|
|
121
|
+
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
|
115
122
|
with:
|
|
116
123
|
registry: ghcr.io
|
|
117
124
|
username: ${{ github.actor }}
|
|
@@ -119,7 +126,7 @@ jobs:
|
|
|
119
126
|
|
|
120
127
|
- name: Extract metadata
|
|
121
128
|
id: meta
|
|
122
|
-
uses: docker/metadata-action@v6
|
|
129
|
+
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
|
123
130
|
with:
|
|
124
131
|
images: ghcr.io/${{ github.repository }}
|
|
125
132
|
tags: |
|
|
@@ -127,7 +134,7 @@ jobs:
|
|
|
127
134
|
type=raw,value=latest
|
|
128
135
|
|
|
129
136
|
- name: Build and push Docker image
|
|
130
|
-
uses: docker/build-push-action@v7
|
|
137
|
+
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
|
|
131
138
|
with:
|
|
132
139
|
context: .
|
|
133
140
|
push: true
|
|
@@ -143,10 +150,10 @@ jobs:
|
|
|
143
150
|
permissions:
|
|
144
151
|
contents: write
|
|
145
152
|
steps:
|
|
146
|
-
- uses: actions/checkout@v6
|
|
153
|
+
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
147
154
|
|
|
148
155
|
- name: Download dist artifacts
|
|
149
|
-
uses: actions/download-artifact@v8
|
|
156
|
+
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
|
150
157
|
with:
|
|
151
158
|
name: dist
|
|
152
159
|
path: dist/
|
|
@@ -160,7 +167,7 @@ jobs:
|
|
|
160
167
|
git push origin "${{ needs.build.outputs.tag }}"
|
|
161
168
|
|
|
162
169
|
- name: Create GitHub Release
|
|
163
|
-
uses: softprops/action-gh-release@
|
|
170
|
+
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
|
|
164
171
|
with:
|
|
165
172
|
tag_name: ${{ needs.build.outputs.tag }}
|
|
166
173
|
generate_release_notes: true
|
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.6] - 2026-10-10
|
|
11
|
+
|
|
12
|
+
### Security
|
|
13
|
+
- Updated UI bundle dependencies with known advisories (seroval, TanStack Router). The runtime (shipped) dependencies that changed are `@tanstack/react-router` 1.168.1 → 1.170.41, with its `@tanstack/router-core` 1.168.1 → 1.171.34, `@tanstack/history` 1.161.6 → 1.162.4, `@tanstack/react-store`/`@tanstack/store` 0.9.2 → 0.11.2 and `cookie-es` 2.0.0 → 3.1.1; and `seroval`/`seroval-plugins` 1.4.2 → 1.6.8, which fixes GHSA-3rxj-6cgf-8cfw, GHSA-hj76-42vx-jwp4, GHSA-mv8w-475r-vwqw, GHSA-p6vx-979v-rg4c and related denial-of-service advisories. seroval is only used by the router's server-side rendering code, which stemtrace doesn't use, and none of it ends up in the built UI bundle. `@tanstack/react-query` also moved 5.90.16 → 5.94.5 (no advisory). Build-time-only packages (Vite, Rollup, PostCSS and others) were updated too.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- Health endpoint: `consumer_connected` reports whether the event consumer's last broker read succeeded (`true`), is failing (`false`), or is unknown (`null`). Only the Redis transport reports it: it detects refused or reset connections, connect timeouts and repeated read timeouts. On redis-py < 8, whose default socket timeout is unbounded, a half-open or hung connection may go unnoticed unless the broker URL sets `socket_timeout` or `health_check_interval`. With RabbitMQ it is always `null`.
|
|
17
|
+
- UI: "Sprout" brand mark in the header and as the favicon (dashboard and login page). The favicon is an inline SVG data URI that follows the OS light/dark theme, so it needs no extra request, is never redirected by form login, and works under any mount prefix. Brand assets live in `docs/brand/`.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- Minimum FastAPI is now 0.112.1 and minimum Starlette 0.38.6: the lowest versions verified by the test suite at release time. FastAPI 0.100–0.104 never worked with current Pydantic (building the app fails with `'FieldInfo' object has no attribute 'in_'`). Starlette is now a declared dependency because stemtrace imports it directly.
|
|
21
|
+
- Minimum redis-py is now 4.1.0, the lowest version verified by the test suite at release time; 4.0.x imports `distutils`, which was removed in Python 3.12.
|
|
22
|
+
- Docker image: Python dependencies are now installed from the project's lockfile, so each image ships the exact versions audited for that release instead of whatever was newest at build time. Base images are pinned by digest, and the UI is built with Node 22.
|
|
23
|
+
- Examples now bind to `127.0.0.1` instead of `0.0.0.0`.
|
|
24
|
+
- Docker image: stemtrace now runs from a virtual environment at `/opt/venv` (it's first on `PATH`), and the base image's unused system `pip` is removed. To add packages in a derived image, use `RUN python -m ensurepip && python -m pip install <package>`, which installs into `/opt/venv`.
|
|
25
|
+
- Docker image: the built-in `HEALTHCHECK` only checks the HTTP status, so a container whose event consumer is degraded (e.g. the broker is unreachable) still reports healthy. Probe `/stemtrace/api/health` and check its `status` field if you need to alert on that.
|
|
26
|
+
- Building from source: the UI build hook now runs `npm ci --ignore-scripts` (or `npm install --ignore-scripts` without a lockfile) instead of `npm install`. Set `STEMTRACE_SKIP_UI_BUILD=1` to skip the UI build entirely; a wheel built that way contains no UI.
|
|
27
|
+
- Health endpoint: `status` is now `"degraded"` instead of `"ok"` when the event consumer died unexpectedly, its loop keeps restarting after errors (such as `WRONGTYPE` or `NOPERM`), or `consumer_connected` is `false`. With RabbitMQ only consumer loop failures are detected. A consumer stopped on purpose, or whose event source finished normally (for example `memory://`), is not degraded. The response is still HTTP 200, so status-code-only health checks behave as before; check the `status` field to alert on a degraded consumer. See the README's "Health Endpoint" section.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- Redis transport: the server stopped receiving events after about 5 seconds of quiet when used with redis-py 8. redis-py 8 defaults `socket_timeout` to 5 seconds, the same as the `XREAD` block window, so the first idle read timed out and the consumer thread exited for good. The `XREAD` block window is now half of the client's effective socket timeout (2.5 seconds with redis-py 8 defaults, 5 seconds when the timeout is unbounded), so idle reads return normally on a single connection. This includes clients passed in directly, such as `redis.Redis.from_url(url)`. The client's own timeouts are unchanged, so publishing from tasks never blocks longer than before.
|
|
31
|
+
- Redis transport: losing the connection (for example a Redis restart, an unreachable host, or a connect timeout) no longer stops event consumption. The consumer logs one warning with a traceback, then one line per attempt, and retries with exponential backoff (1 s doubling to a 30 s cap, reset on success), resuming from the last stream entry it read. Repeated read timeouts are logged as warnings at most once a minute.
|
|
32
|
+
- Server: the event consumer thread restarts with the same backoff after an unexpected error instead of exiting silently, and `stop()` interrupts a pending reconnect wait instead of leaving the thread behind.
|
|
33
|
+
- UI: the favicon no longer 404s (the dashboard referenced a non-existent `/vite.svg`).
|
|
34
|
+
- UI: JS and CSS assets no longer 404 on FastAPI 0.137+ when stemtrace is installed with per-file symlinks (e.g. `uv pip install --link-mode symlink`). The `/assets` mount now follows symlinks inside the bundle; request paths are still confined to the assets directory.
|
|
35
|
+
|
|
10
36
|
## [0.3.5] - 2026-10-09
|
|
11
37
|
|
|
12
38
|
### Security
|
|
@@ -122,7 +148,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
122
148
|
- **E2E test suite**: Docker API tests + Playwright browser tests
|
|
123
149
|
- **Comprehensive test suite**: 350+ Python tests, 90%+ coverage
|
|
124
150
|
|
|
125
|
-
[unreleased]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.
|
|
151
|
+
[unreleased]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.5...HEAD
|
|
152
|
+
[0.3.5]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.4...v0.3.5
|
|
153
|
+
[0.3.4]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.3...v0.3.4
|
|
154
|
+
[0.3.3]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.2...v0.3.3
|
|
155
|
+
[0.3.2]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.1...v0.3.2
|
|
156
|
+
[0.3.1]: https://github.com/iansokolskyi/stemtrace/compare/v0.3.0...v0.3.1
|
|
126
157
|
[0.3.0]: https://github.com/iansokolskyi/stemtrace/compare/v0.2.2...v0.3.0
|
|
127
158
|
[0.2.2]: https://github.com/iansokolskyi/stemtrace/compare/v0.2.1...v0.2.2
|
|
128
159
|
[0.2.1]: https://github.com/iansokolskyi/stemtrace/compare/v0.2.0...v0.2.1
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# stemtrace server Dockerfile
|
|
2
|
+
# Multi-stage build for smaller production image
|
|
3
|
+
|
|
4
|
+
# Stage 1: Build frontend
|
|
5
|
+
FROM node:22.23.3-alpine3.24@sha256:0a7108bf6c7bf5de370ffb1a3ed6be93d405b43ff159f681a8d18c0e2bc2e402 AS frontend-builder
|
|
6
|
+
|
|
7
|
+
WORKDIR /app/frontend
|
|
8
|
+
COPY src/stemtrace/server/ui/frontend/package*.json ./
|
|
9
|
+
RUN npm ci --ignore-scripts
|
|
10
|
+
|
|
11
|
+
COPY src/stemtrace/server/ui/frontend/ ./
|
|
12
|
+
RUN npm run build
|
|
13
|
+
|
|
14
|
+
# Stage 2: Build a virtualenv with the locked dependencies and stemtrace itself
|
|
15
|
+
FROM python:3.12.14-slim-trixie@sha256:f77ac9e44ae96ef2c90b8053ea08c31f8be030f824196b0ae4db6d462c84e51f AS builder
|
|
16
|
+
|
|
17
|
+
COPY --from=ghcr.io/astral-sh/uv:0.12.18@sha256:3adc3706091ce7c2fe595e669628caedd6d951551b92b258b7e7dbe06d9440bc /uv /usr/local/bin/uv
|
|
18
|
+
ENV UV_PYTHON_DOWNLOADS=never \
|
|
19
|
+
UV_PROJECT_ENVIRONMENT=/opt/venv \
|
|
20
|
+
UV_NO_CACHE=1
|
|
21
|
+
|
|
22
|
+
WORKDIR /app
|
|
23
|
+
|
|
24
|
+
# Install locked runtime dependencies from wheels only (cached layer)
|
|
25
|
+
COPY pyproject.toml uv.lock ./
|
|
26
|
+
RUN uv sync --locked --no-build --no-install-project && rm -f /opt/venv/.lock
|
|
27
|
+
|
|
28
|
+
# Copy source
|
|
29
|
+
COPY README.md LICENSE build_ui.py ./
|
|
30
|
+
COPY src/ src/
|
|
31
|
+
|
|
32
|
+
# Copy pre-built frontend
|
|
33
|
+
COPY --from=frontend-builder /app/frontend/dist/ src/stemtrace/server/ui/frontend/dist/
|
|
34
|
+
|
|
35
|
+
# Build and install stemtrace itself (non-editable) into the virtualenv
|
|
36
|
+
RUN uv sync --locked --no-build --no-editable && rm -f /opt/venv/.lock
|
|
37
|
+
|
|
38
|
+
# Stage 3: Production image
|
|
39
|
+
FROM python:3.12.14-slim-trixie@sha256:f77ac9e44ae96ef2c90b8053ea08c31f8be030f824196b0ae4db6d462c84e51f AS production
|
|
40
|
+
|
|
41
|
+
WORKDIR /app
|
|
42
|
+
|
|
43
|
+
COPY --from=builder /opt/venv /opt/venv
|
|
44
|
+
ENV PATH="/opt/venv/bin:$PATH"
|
|
45
|
+
|
|
46
|
+
# Drop the base image's system pip: stemtrace runs from /opt/venv and never
|
|
47
|
+
# uses it, and it would otherwise ship known advisories. `python -m ensurepip`
|
|
48
|
+
# still works for derived images (see CHANGELOG).
|
|
49
|
+
RUN /usr/local/bin/python -m pip uninstall --yes --quiet pip \
|
|
50
|
+
&& rm -f /usr/local/bin/pip /usr/local/bin/pip3 /usr/local/bin/pip3.12
|
|
51
|
+
|
|
52
|
+
# Create non-root user
|
|
53
|
+
RUN useradd -m -u 1000 stemtrace
|
|
54
|
+
USER stemtrace
|
|
55
|
+
|
|
56
|
+
# Default environment
|
|
57
|
+
ENV STEMTRACE_BROKER_URL=""
|
|
58
|
+
ENV HOST="0.0.0.0"
|
|
59
|
+
ENV PORT="8000"
|
|
60
|
+
|
|
61
|
+
EXPOSE 8000
|
|
62
|
+
|
|
63
|
+
# Health check (CLI server mounts API at /stemtrace prefix)
|
|
64
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
|
65
|
+
CMD python -c "import httpx; httpx.get('http://localhost:8000/stemtrace/api/health').raise_for_status()"
|
|
66
|
+
|
|
67
|
+
# Default command: run server
|
|
68
|
+
ENTRYPOINT ["stemtrace"]
|
|
69
|
+
CMD ["server", "--host", "0.0.0.0", "--port", "8000"]
|