Skip to content

v0.13.3

Choose a tag to compare

@github-actions github-actions released this 22 Oct 23:11
· 284 commits to main since this release
b846580

Fixed

  • Starting a fresh AI-batch source scan (e.g. of /downloads) no longer fails immediately with "ERROR: expected_revision is required to update existing batch …". _start_ai_batch_job creates — and bumps the revision of — the batch's durable store row before it unblocks the worker thread, but on a fresh (non-recover) run the worker's _run_ai_batch_import built a brand-new _ai_batch_initial_state, which carries no revision. Its first _ai_batch_commit therefore attempted an un-revisioned update of the already-existing row, which the ARCH-010 optimistic-concurrency (CAS) contract correctly rejects. The worker now loads the persisted row first (for the non-recover path too) and threads its current revision through every commit, so the scan proceeds and the stale-writer guard stays fully intact. The CAS contract itself is unchanged — an un-revisioned update of an existing batch is still refused; the fix is in the caller, which now passes the revision the state was last read at. Regression test: tests/test_ai_batch_retry_race.py::FreshBatchSourceScanRevisionTests.

Added

  • TEMPORARY boot-trust diagnostic (to be removed once the live cause is confirmed). When the folder-MBID resolver's Lidarr call is REJECTED by the outbound URL policy (ProviderOutcome.REJECTED), backend.lidarr_rgid_resolver now emits a single WARNING (once per process) capturing, from the live serving process's own job thread, why the configured-URL trust was not active there: configured_url("lidarr"), whether a resolver is registered and its value, backend.app_runtime.LIDARR_URL, the recomputed implicit_rule_for_url(configured_url) (would_trust_rule), the live _TRUSTED_RULE, and the id()s of the backend.app_runtime / backend.security / backend.provider_boundary module objects. It logs only non-secret base URLs (userinfo stripped) and rule/module ids — never the Lidarr API key — fires only on the rejection, and changes no behavior otherwise. Diagnoses whether the live cause is the empty-resolver shadow (fixed below) or a duplicate module instance; remove after the v0.13.3 deploy confirms it.

Fixed

  • A provider's configured-URL trust can no longer be lost in the long-lived serving process when its registered resolver comes back empty. The outbound boundary grants each operator-hosted provider implicit trust of its own configured URL (provider_boundary.configured_url), resolved either from a registered resolver (Plex, Lidarr) or, as a robust fallback, from the backend.app_runtime constant the service actually calls (_RUNTIME_URL_CONSTANTS: Lidarr, slskd, qBittorrent, yt-dlp PO). A registered resolver that returned "" — e.g. a module-level closure in a route module that loaded before the setting was present, which is exactly how the running server could differ from a fresh import app — previously shadowed that fallback, so the configured URL earned no trust and the provider's own call to a private-LAN address (the Lidarr folder-MBID resolver's 192.168.0.250:8686, ProviderOutcome.REJECTED, "blocked by outbound URL policy") was rejected. configured_url now falls through to the _RUNTIME_URL_CONSTANTS / sys.modules["backend.app_runtime"] value whenever the resolver yields nothing, so registering a resolver can only ADD a trust source, never remove the one the provider already had. Trust stays scoped to exactly the one configured scheme/host/port; the SSRF guard is unchanged for every other address and provider. New real-app-context regression tests (tests/test_lidarr_trust_boot_activation.py) boot the app the way the server does and assert the Lidarr configured URL is admitted through provider_boundary.opened end to end, including on a worker thread (the job engine runs jobs on threads), plus the resolver-fallthrough guard.