Skip to content

v0.3.0 — Python 3.14, security backlog cleared, Maple Mono UI

Choose a tag to compare

@fdff87554 fdff87554 released this 21 Sep 06:42
· 230 commits to main since this release
9c2dc2b

Maintenance and hardening release on top of v0.2.3. The backlog of 13 stale Dependabot PRs is cleared, every known vulnerability in both lockfiles is gone, the runtime moves to Python 3.14, and the release pipeline no longer publishes images that failed CI.

No API changes. /api/info and /api/download behave exactly as before — verified against a real video on every step of the way.

⚠️ Breaking for local development

requires-python is now >=3.14 and mise.toml pins python = "3.14". Contributors on 3.12 will need to re-run mise install and rebuild .venv. Container users are unaffected: the image ships its own interpreter.

If mise install fails with Python installation is missing a 'lib' directory, your mise is too old to pick the right precompiled CPython flavor for 3.14 — run mise self-update (fixed as of 2026.9.12).

Security

pip-audit --strict went from 15 vulnerabilities across 3 packages to 0; npm audit from 5 (3 high, 2 moderate) to 0. None of the vulnerable code paths were reachable from this service's API, but they gated CI and all sat on the request path.

Package Fixed Advisories
yt-dlp 2026.3.17 → 2026.8.19 GHSA-69qj-pvh9-c5wg, CVE-2026-50019, CVE-2026-50023, CVE-2026-50574, CVE-2026-55404
starlette 1.2.1 → 1.6.0 CVE-2026-54283 (high), CVE-2026-54282
anyio 4.13.0 → 4.15.1 CVE-2026-63374 (critical), CVE-2026-64847
postcss 8.5.15 → 8.5.28 CVE-2026-73646 (high), CVE-2026-69153
nanoid 3.3.12 → 3.3.19 CVE-2026-67214, CVE-2026-67213
ws (via happy-dom) 8.20.0 → 8.21.3 GHSA-96hv-2xvq-fx4p (high)
node (build stage) 26.3.0 → 26.9.0-alpine covers the 26.3.1 and 26.5.1 security releases

Hardening: yt-dlp subprocesses now pass --ignore-config (#81). A yt-dlp.conf picked up from ~/.config/yt-dlp, ~/.yt-dlp, /etc/yt-dlp or beside the binary could otherwise inject --exec, an external downloader, a cookie file, or -P/-o — the last of which would write media to disk and break the project's no-disk-I/O guarantee.

Repository settings: Dependabot alerts and security updates are now enabled. Every advisory above is transitive, so none of them would have opened a PR on their own.

Runtime

  • Python 3.12.13 → 3.14.7 (#74), with mise.toml, requires-python, ruff's target-version, both Dockerfile stages, the README and both lockfiles moved together. Regenerating the lockfiles under 3.14 changed no package versions.
  • Deno bin-2.8.2 → 2.9.7 (#51) — the JS runtime yt-dlp uses for YouTube player challenges.
  • uvicorn 0.49.0 → 0.53.0 (#73, #75), fastapi 0.136.3 → 0.141.1 (#72).

fastapi 0.137 turned router.routes into a tree, which changes how slowapi's middleware resolves handlers. The outcome is unchanged — rate limiting is performed by the @limiter.limit decorators either way — and test_returns_429_after_info_limit_exceeded covers it.

Interface

  • The UI is now set in Maple Mono (#78), by name only. No webfont is shipped: the CN build is 20.4 MB per weight with no upstream woff2, and a CDN would leak viewers' IPs, which is the opposite of what this service is for. Anyone with the font installed sees it; everyone else gets their platform's monospace face. CJK video titles fall back cleanly to the system face.

Build and release pipeline

  • GHCR publishes only after CI passes (#77). The publish job used to trigger on push to main independently of every check — during this release cycle alone it would have published ~13 times, several while the audit was red. It is now a needs-gated job inside ci.yaml, and CI also runs on v* tags so a tagged release is validated before it ships. This release is the first to go through that path.
  • npm audit and pip-audit are separate jobs (#77). As sequential steps, a frontend finding aborted the run before pip-audit ever executed, so a red X said nothing about the backend.
  • Dependabot is grouped and labelled (#76). The five labels the config had always requested did not exist, so every PR got a complaint comment instead. npm dev-dependencies group by minor+patch, tailwindcss and @tailwindcss/* are pinned to the same group (updating one alone leaves a nested duplicate in the lockfile), docker patches group, actions group. pip stays ungrouped on purpose — its lockfiles must be regenerated by hand, one package at a time.

Toolchain

vitest 4.1.6 → 5.0.1, TypeScript 6.0.3 → 7.0.2, vite 8.0.12 → 8.3.0, happy-dom 20.9.0 → 20.14.5, tailwindcss 4.3.0 → 4.3.3, actions/cache v5 → v6, actions/checkout v6 → v7. All dev-only; the emitted bundle is byte-identical across the TypeScript 7 migration.

Verification

Every change in this release was checked against a real video through the full Docker stack, not just unit tests — the backend suite mocks yt-dlp, so version bumps to it cannot be validated any other way. /api/info returns 6 formats, /api/download returns valid mp4 and mp3 streams, and container logs are unchanged from the v0.2.3 baseline.

Backend 56 tests, frontend 20 tests, pre-commit run --all-files clean.

Pull the image

docker pull ghcr.io/fdff87554/youtube-downloader:0.3.0
# or the floating minor tag:
docker pull ghcr.io/fdff87554/youtube-downloader:0.3

Digest: sha256:aa46bcd6fb62c67d2192e6c1bfda08a7875f88b584435071d25d410541daa8af

Run command and configuration are unchanged from v0.2.0 — see that release for the full setup notes.