Skip to content

chore: sync develop with main - #576

Closed
github-actions[bot] wants to merge 2 commits into
developfrom
main
Closed

chore: sync develop with main#576
github-actions[bot] wants to merge 2 commits into
developfrom
main

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

@coderabbitai ignore

develop has drifted behind main (releases, fixes, dependency bumps). Do not merge this PR — it reports the drift, it does not fix it.

develop requires branches be up to date, and head:main can never satisfy that without pulling develop's extension files into main, which the branch invariant forbids. Squash or rebase would also leave main unreachable from develop, so this workflow would just open another PR next push.

Sync locally instead:

git checkout develop && git merge origin/main && git push

Then verify git diff main develop is added extension files plus deploy/docker/Dockerfile only. GitHub marks this PR merged on its own once develop contains main's tip. Opened by the sync-develop workflow.

chodeus and others added 2 commits August 18, 2026 09:32
… density (#575)

UnmatchedAssetsPage's two hand-rolled pill rows become the shared
component (tablist roles for free); the two flagged flex-1 segments get
the min-w-11 pin; the assets grid drops one column per breakpoint so
every tile hosts the 44px 3-action bar — the 2-up-on-phones rule applied
consistently.
)

* fix(cl2k): harden Plex token/SSRF, filename + season-batch safety, negative caching (#500)

Security + correctness hardening for the develop-only CL2K maker: Plex token-leak + SSRF-path fixes, tmdb_id-or-backdrop validator (fixes the TVDB/IMDB-only 422), blank-title dotfile guard, transient-failure negative-caching fixes, AI-unavailable refusal, season-batch bounding, and the Dockerfile node-digest invariant restore. Includes CodeRabbit review fixes (double-checked ORT session lock, external_ids 404-caching) and validator dedup.

* fix(cl2k): resource hardening — linear despeckle, bounded decodes, capped text detection (#510)

* fix(cl2k): resource hardening — despeckle merge, decode caps, probmap bound

- _despeckle: two-pointer merge over the sorted run lists (O(n) per row, was
  O(n^2)); output proven byte-identical to the old pairwise scan (oracle test,
  400 randomized trials) — 11x on the pathological many-runs fixture
- limits.py owns decode safety: header-only megapixel ceiling before any
  convert (a bomb is rejected from the IHDR, never decompressed) and wand
  ResourceLimits at the sole entry point (IM ships unlimited without a
  policy.xml outside the container); all eight decode sites route through it
- detect_text_probmap: work at a bounded 2048 side and return the working-size
  map (the one consumer rescales anyway) — peak level buffers drop from
  ~900MB on a 10000-square source to ~32MB, with the network input dims
  proven unchanged

* test: hoist the header-size read out of the assert; docstrings on the new tests

CodeQL flags side-effecting asserts (alert 295); the read moves to a statement.
Every test this branch adds now carries a one-line docstring.

* docs: trim the limits module docstring and despeckle note to the contract

* fix(cl2k): render fidelity + endpoint robustness — PSD parity, deferred uploads, honest batch status (#512)

* fix(cl2k): render fidelity + endpoint robustness batch

Fidelity: /psd-export threads the uploaded/brushed art (was TMDB-only); the
PSD logo pipeline now IS renderer.process_logo (four drifting Pillow mirrors
deleted; LOGO layer pixel-identical to the render); save-as-is encodes once
(borders fold into the overlay draw); the runtime image keeps cairosvg (main's
rasterize step uninstalls its build-only copy, stripping the cl2k pin).

Robustness: saving + square/background preview endpoints share the poster
preview's error handling (clean 400s, one owner); Drive uploads defer whenever
defer_upload is supplied and /retext carries BackgroundTasks (no more inline
rclone 504s); season snapshots copy the live results list; seasons-status
reports failed + outcome and escalates an all-failed batch to error; the SVG
sniff catches BOM/DOCTYPE/comment prefixes (cairosvg's unsafe=False path);
whitespace titles skip the wordmark instead of 500ing inside the handler;
brush flip/erase failures log instead of silently dropping the user's edits.

* fix(cl2k): keep exception text out of extension responses; drop wrapper lambdas

_failed owns the pattern (stable message + logged detail) across 24 sites in
both extension routers, including the season-job registries /seasons-status
serialises to the browser; four pure-wrapper lambdas replaced with the
callable (CodeQL).

* fix(cl2k): review round — config faults reach the shared handler, deferred crashes report

poster_self_heal loads config outside the save guard; a deferred Drive-only
run that crashes before the upload loop reports through the failure path
instead of leaving upload_pending forever; cairosvg's pin lives only in
requirements-cl2k.txt (pure-insertion re-run); unsafe=False passed explicitly;
docstrings on every diff-touched function.

* test: exercise the /retext deferred-upload path end to end

The prior coverage asserted signatures only; this runs the real chain and
proves nothing uploads inline, the task rides BackgroundTasks, and the
deferred callable performs the upload. All three threading hops
mutation-checked.

* fix(cl2k): maker-page sweep — brush persistence, race guards, honest failure states (#513)

* fix(cl2k): maker-page sweep — brush persistence, race guards, error states

- HistorySection owns no second collapse (the four call-site accordions do);
  brush masks thread back on every reopen (all 7 BrushMask sites); the manual
  preview aborts and sequences like the auto-render effect
- one readFileAsDataURL helper with onerror/onabort behind all 10 reader
  sites; onExtract rejects instead of spinning forever; the GDrive logo picker
  is a real state machine (needs-title / retryable error / loading / empty)
- mounted-ref invariant gets one owner (useMountedRef); the as-is poll gains
  its missing mounted check; as-is re-encoding caches on the image identity;
  PosterHeal rows disable while any apply is in flight; downloadBlob defers
  the revoke past WebKit's click handling
- seasons toasts read the new failed/outcome fields additively (partial ->
  warning with counts) and the deferred-save comments tell the truth

* fix(cl2k): unmount and race refinements from review

Preview cleanup invalidates the sequence before aborting; the GDrive error
scopes to its query; as-is source reads reject inside their error boundaries
(and non-OK fetches reject before base64ing an error body); both season polls
share one pollSeasonsBatch owner with post-request mounted checks and guarded
finally blocks.

* fix(cl2k): as-is unmount guards + effect-owned request aborts (#513 follow-up) (#514)

fix(cl2k): as-is handlers respect unmount; effects abort their requests

Mounted-ref checks follow every as-is await (the panel unmounts on a build-tab
switch, not just navigation); save feedback stays loud since a completed save's
outcome is known. The auto-preview and history effects own AbortControllers and
the wrappers forward signals (spread after the AI timeout so it survives).
browsePosters abort needs a main-side wrapper change — ledgered.

* refactor(cl2k): one GDrive picker owner — unified state machine, −147 lines (#519)

* refactor(cl2k): one GDrive picker owner

A and B were byte-identical twins; copy co-varies with the asset kind, so
kind is the single discriminator (GDRIVE_KINDS) and useGdriveBrowse owns the
fetch/error/import machinery. Both poster sites gain the retryable error
state; net -147 lines, page chunk shrinks.

* fix(cl2k): abort and revision-guard the picker import path

A stale full-res import resolving after a source change re-applied the
cleared asset — wiping fresh framing or a painted brush mask (pre-existing at
all three sites; the unified hook makes one fix cover them). Signal threads
to the fetch; the revision covers the FileReader window; the abort ref is
deliberately not nulled so an aborted elder can't strip a newer import's
spinner.

* refactor(cl2k): one ArtCard owner for the picker card shell (#530)

UploadArtCard, Picker and GDrivePicker each carried a byte-identical card
shell (header + chosen-file row). ArtCard owns it now — children is the
pre-choice body, footer the GDrive importing note, customAlt the img alt.
All six UploadArtCard call sites are untouched.

* fix(cl2k): art picker resolves a tvdb/imdb-only title instead of demanding tmdb

/images, /season-images and /external-ids hard-required tmdb_id while the
rest of the module treats ids as any-of-three, so opening the picker for a
title without one logged a 422 and returned no TMDB art — even when the
title's tvdb id could resolve to one. They now take all three ids
optionally and resolve through the same lookup /details already used
(one owner now, four call sites). No ids at all degrades to empty art
rather than an error. The page passes the tvdb/imdb ids it already had in
scope, and the external-ids backfill no longer skips a tvdb-only title.

* fix(cl2k): narrow the PSD version-info except and say why it passes

py/empty-except 270: a bare 'except Exception: pass' hid whether the flag
write was optional or a swallowed bug. VERSION_INFO is optional metadata,
so the save must not fail over it — narrowed to the three errors psd_tools
raises when the resource or the import is absent.

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 94b9734 (#553)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 94b9734

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to f35be93 (#555)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to f35be93

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to d983dc5 (#557)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to d983dc5

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to a84bf7d (#559)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to a84bf7d

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to aca8810 (#561)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to aca8810

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 78759fa (#563)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 78759fa

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 492e24a (#565)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 492e24a

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to f65cbad (#567)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to f65cbad

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 71731f2 (#569)

chore(deps): update ghcr.io/chodeus/chub:latest docker digest to 71731f2

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* feat: one branch, two images — :latest stays lean, :full carries the extensions

The develop branch's extensions (CL2K maker, poster self-heal) move to
main behind a runtime gate: CHUB_IMAGE_FLAVOR=lean turns off every
extension's functional hooks, and cl2k additionally requires its
renderer deps to import. Config fields and tables always register, so a
config written under :full loads, types and round-trips under :latest.

The Dockerfile builds both finals from a shared runtime-base; CI
publishes :latest and :full (+ -full release tags, :develop as a
deprecated alias). The branch model's machinery — sync workflow, both
guards, renovate develop scoping — is deleted.

* fix: review hardening across the migrated extension code

Markup-leading logo bytes always take the sandboxed cairosvg path (a
long prologue defeated the <svg scan and reached ImageMagick's XML
delegates). Drive OAuth credentials ride RCLONE_* env instead of argv,
every rclone call gets a timeout, sidecar posts stop following
redirects, request-image decodes go through open_bounded, an unknown
asset_type no longer defaults to movie, empty local_dirs no longer
purges every proposal, and the full-image sha tag is gated to the
default branch so branch pushes stay lean-only.

* fix: apply the review's classes repo-wide

sync_gdrive carried the same credential-in-argv shape — worse, it logs
the quoted command at debug — so its OAuth trio rides RCLONE_* env too.
One raster-only choke point at the maker's b64 boundary keeps markup out
of every non-logo Wand decode; only the logo field may carry SVG, and
the renderer sandboxes that.

* test: pin the rclone timeout guard

The stub asserts the ceiling reaches subprocess.run and the conversion
raises RuntimeError — dropping either lever reddens it.

* fix(deps): pin scipy above PYSEC-2023-102

psd-tools[composite]'s transitive floor (1.9.3) trips the newly-audited
requirements-cl2k.txt; 1.18.0 carries cp314 wheels.

---------

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@chodeus

chodeus commented Aug 18, 2026

Copy link
Copy Markdown
Owner

The sync-develop model is retired (#577): one branch, no back-merges. This was the workflow's final notification PR; the workflow itself is deleted.

@chodeus chodeus closed this Aug 18, 2026
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