- match_bangumi_in_list: also accept a torrent whose rebuilt title equals
the stored title_raw (#1103, #1114)
- download_bangumi / collect_season: drop items whose season or type
conflicts with the bangumi (#1105)
- request_url: swap in a fresh shared client on PoolTimeout without
closing the old one (#1104)
- classic parser: Unicode Roman numeral season, strip fullwidth dash
wrapper (#1108)
- Docker HEALTHCHECK: healthcheck.py reads the configured WebUI port and
probes IPv4 then IPv6 loopback (#1106)
- scheduler: non-positive interval falls back to 1s; deploy docs cap
container logs at 10 MB x 3 (#1117)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KU9GqKzULrNb7MN5T9TYix
Two changes, verified with local builds:
- Drop UV_COMPILE_BYTECODE=1: shipped .pyc files were 51MB. The venv is
root-owned and the app runs long-lived as 'ab', so bytecode only saved
a few seconds of import time once per container start. This also
matches the boot_overlay uv-sync path, which never compiled bytecode.
- mcp[cli] -> mcp: the app only imports mcp.server; the cli extra pulled
typer/rich/pygments/markdown-it (~14MB) for an unused console script.
python-dotenv, the extra's other member, is already a direct dep.
Compressed pull size drops 64.2MB -> 48.8MB. Image verified: packages
absent, no __pycache__, 'import main' succeeds; pytest and mypy green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEnmRvBJL93fAURbRf1koK
Closes the update-chain trust gap: the sha256 came from the same GitHub
release as the bundle (integrity, not authenticity), and the boot overlay
re-applied ab-writable content as root — including uv sync on an
attacker-controllable lockfile.
- signing: new module/update/signing.py verifies an ed25519 signature;
public key embedded in the image at /app/ab_update_pubkey.pem (outside
the overlay-replaceable tree, so it is the trust root). Private key lives
only in CI (UPDATE_SIGNING_KEY secret).
- updater: discover the .zip.sig asset, verify the signature after the
sha256 check, reject any release without a signature, retain the verified
bundle.zip+.sig for boot re-verification, and swap them on rollback.
- boot_overlay: re-verify the signed bundle at every boot and extract the
module tree / webui dist FROM the verified zip — never from the
ab-writable current/ tree; read the version from the zip manifest, not
the ab-writable applied.json; drop to the ab user before any fallback
uv sync so lockfile build hooks can't run as root; zip-slip guard uses
is_relative_to (also fixed in updater._safe_extract).
- CI: build.yml signs the bundle with UPDATE_SIGNING_KEY and publishes the
.zip.sig; the build fails if the secret is unset.
- deps: cryptography made an explicit dependency.
Tests cover bad-signature reject, unsigned-release reject, legacy overlay
without a signed bundle reject, verified-bundle retention, and boot-overlay
signature verification. Full backend suite: 1079 passed.
Ops: run `gh secret set UPDATE_SIGNING_KEY < ~/.autobangumi/update-signing-key.pem`
before the 3.3 release.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FAxVyRwrY7z5NotTtgnwVs
Adds one-click update from the settings page so routine updates no
longer require pulling a new Docker image.
- CI attaches update-bundle-<version>.zip (+ .sha256) to each release:
backend module tree, built webui, and a manifest; the image bakes
/app/IMAGE_VERSION as the baseline
- boot_overlay.py (shipped in the image, outside /app/module so it can
never overwrite its own deciding logic) runs from entrypoint before
the app starts: if a persisted overlay in /app/config/updates is
newer than the image it tree-replaces /app/module and /app/dist and
runs `uv sync` when the lockfile changed; if the image is newer it
clears the stale overlay. Applied via the config volume, so updates
survive container recreate; a newer pulled image always wins
- GET/POST /api/v1/update/{check,apply,rollback} (auth-gated, repo
pinned to EstrellaXD/Auto_Bangumi): check queries GitHub releases
with a stable/beta channel; apply downloads, verifies sha256, stages,
promotes current->backup, then exits the process so Docker restarts
into the overlay; rollback swaps the backup back. Progress streams
over the existing SSE channel
- Settings card (Log page) shows current/latest, release notes, channel
toggle, update + rollback, with a restart:unless-stopped requirement
note; compose examples updated
Requires restart: unless-stopped for self-restart (documented; no
Docker-socket fallback). 1043 backend tests, mypy 0, ruff clean; 135
frontend tests, vue-tsc clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTnuEgR78cBk32bLNKar3z
Add GET /health mounted outside the /api prefix so it bypasses
per-route auth and is reachable as a plain liveness/readiness probe.
Returns {status, version, db_ok}, degrading to db_ok=false with a 200
(not a raised exception) on database failure so the probe stays useful
even when the DB is unreachable. Add a Docker HEALTHCHECK that curls it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTnuEgR78cBk32bLNKar3z
- Update requires-python to >=3.13 in pyproject.toml
- Update ruff and black target versions to py313
- Update Dockerfile to use python:3.13-alpine
- Add explicit Python 3.13 setup in CI workflow
- Regenerate uv.lock for Python 3.13
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace pip + requirements.txt with uv for dependency management.
- Multi-stage Dockerfile using ghcr.io/astral-sh/uv builder image
- CI updated to use astral-sh/setup-uv@v4
- Ruff config moved to [tool.ruff.lint] (fixes deprecation)
- Transitive deps removed, missing direct deps added (requests, PySocks, urllib3)
- Database layer migrated to async (AsyncSession + aiosqlite)
- Tests updated to match async database interface
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>