Skip to content

[fixes] Dependency refresh, lock hardening, entity tasks endpoint#1075

Open
frankrousseau wants to merge 15 commits into
cgwire:mainfrom
frankrousseau:main
Open

[fixes] Dependency refresh, lock hardening, entity tasks endpoint#1075
frankrousseau wants to merge 15 commits into
cgwire:mainfrom
frankrousseau:main

Conversation

@frankrousseau
Copy link
Copy Markdown
Contributor

Problems

  • Pinned dependencies were drifting from latest stable (security + bug fixes left on the table)
  • Custom Redis lock duplicated logic redis-py 7.x now provides natively, and annotation/playlist-build paths weren't lock-safe
  • Playlist shared-membership endpoint loaded full preview-file payloads on every check
  • for_entity on playlists accepted arbitrary values, and "episode" was missing from the allowed set
  • No bulk endpoint to create multiple tasks on an entity in one call

Solutions

  • Bumped redis, bcrypt, flask-cors, tabulate plus all PATCH/MINOR/year-cal pins; ran black 26
  • Replaced custom Lua lock with redis-py's native Lock; abort annotation update on lock failure; reject concurrent playlist build enqueues
  • Drop preview-file enrichment from the shared-membership check
  • Validate for_entity against the supported set and add "episode" to it
  • Add POST /data/entities/<id>/tasks validating against project + asset-type workflows

frankrousseau and others added 15 commits May 12, 2026 16:15
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PATCH: click, flask, flask-jwt-extended, flask-socketio, gazu,
opencv-python, orjson, psycopg, python-socketio, sqlalchemy, ua-parser,
werkzeug, pytest.

MINOR: discord.py, fido2, flask-caching, meilisearch, numpy, pillow,
pydantic, requests, rq, spdx-license-list, tomlkit, fakeredis,
pytest-cov.

Year-cal: gevent 25→26 (drops Python 3.9, zou is 3.10+), gunicorn 25→26
(drops eventlet worker, zou uses gevent), black 26.1→26.3 (no style
delta), pytz 2025→2026 (tzdata).
Both majors are safe for zou:
- flask-cors 6.0.0 path-matching CVE fixes (regex specificity, unquote,
  case sensitivity) don't affect the single catch-all r\"/*\" pattern
  used here.
- tabulate 0.10.0 only drops Python <3.10 and renames the PRESERVE_STERILITY
  global, which is not used in zou.
bcrypt 5.0.0 raises ValueError when hashpw receives a password longer
than 72 bytes (previously truncated silently). zou already truncates to
72 bytes in auth.encrypt_password, and the only other hashing call site
(hash_recovery_codes) operates on 10-byte ASCII codes — so no caller
path is at risk.
zou only uses redis-py's standalone StrictRedis (pub/sub, cache, RQ
queues, locks, auth tokens) — no cluster, no SSL, no sorted-set
commands, no RediSearch/Gears/Graph. The 6.x removals (charset/errors
args, RedisGears, RedisGraph) and 7.x internal cleanups don't touch any
call site here.

The only observable behavior change is the new default retry strategy
on standalone clients (3 retries with exponential backoff), which adds
resilience to transient Redis hiccups at the cost of a slightly longer
failure mode when Redis is permanently down.
The custom acquire_lock/release_lock pair plus the Lua release script
in redis_lock.py reimplemented exactly what redis-py exposes as
Redis.lock(name, timeout, blocking_timeout). Replace the internals with
the built-in primitive; the public with_lock / with_playlist_lock /
with_preview_file_lock context managers keep the same signature so
callers (playlists_service, preview_files_service) are unchanged.

50 lines of custom locking code removed (Lua + uuid identifier + poll
loop); semantics preserved.
Enqueue the build worker with unique=True and a deterministic job_id
keyed on the playlist. A second build kicked off while the first is
still queued or running raises DuplicateJobError; we roll back the
freshly created BuildJob row and return 409 so the UI can surface the
conflict instead of spawning a parallel render. Short result/failure
TTLs (60s) keep legitimate rebuilds unblocked once the previous job
settles.
… check

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gazu's create_entity_tasks (and create_shot_tasks, create_concept_tasks)
posts to data/entities/<id>/tasks with {"task_type_ids": [...]} but no
matching route existed on zou, so calls 404'd. Add the missing route on
the entities blueprint.

Each task type is validated before creation:
- TaskType.for_entity must match the entity kind (Asset / Shot / ...).
- Task type must be enabled on the entity's project (ProjectTaskTypeLink).
- If the entity is an asset, task type must be in the entity's asset
  type workflow (TaskTypeAssetTypeLink).

Existing tasks for the same (entity, task_type) pair are skipped, in
line with the per-task-type bulk create routes.
The column is permissive (String(10), no whitelist), so adding "edit"
to the set of supported values does not require any code change here.
Add a parameterized test that pins shot/asset/sequence/edit round-trip
through the HTTP API to lock the contract for consumers (gazu Literal,
kitsu UI).
The column is a permissive String(10), but consumers (gazu Literal,
kitsu UI branches, docs) all assume a closed set: shot, asset,
sequence, edit. A stray value previously slipped through and rendered
as a misleading default downstream.

Whitelist the four supported values in playlists_service and reject
anything else at the CRUD boundary on both create and update, with a
clear 400. Existing rows are untouched.
TV-show productions need a way to review final episode cuts side by
side, the same way edits unlocked end-to-end review. Widen the
whitelist and the round-trip test to cover episode alongside the four
existing values.
numpy 2.3+ dropped Python 3.10 support, breaking CI for the 3.10 leg of
the test matrix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant