Skip to content

fix: address open issues #169 (version), #170 (XSS), #173 (SSRF) - #176

Merged
thcp merged 5 commits into
mainfrom
fix/open-issues-triage
Jun 2, 2026
Merged

thcp merged 5 commits into
mainfrom
fix/open-issues-triage

Conversation

@thcp

@thcp thcp commented Jun 2, 2026 •

Copy link
Copy Markdown
Collaborator

Addresses three open issues in one branch.

#170 — Stored XSS via library folder names

folder.name was interpolated raw into innerHTML in the folder render path while the track paths already escape. Now escaped with the existing esc() helper (static/js/catalog.js).

#173 — SoundCloud SSRF surface

  • Drop on.soundcloud.com (the share shortener → redirects to arbitrary targets) from the host allowlist.
  • Add a yt-dlp extractor allowlist (allowed_extractors=["youtube","soundcloud"]) so a URL slipping past host validation can't invoke the generic extractor / arbitrary network target.
  • app/pipeline/download.py; test updated (on.soundcloud.com now rejected).

#169 — Version stuck at 0.6.0-alpha.2 for source/Docker/self-hosted

Make the git tag the single source of truth via hatch-vcs — no version is hand-edited.

  • pyproject.toml → dynamic = ["version"] + hatch-vcs (writes app/_version.py at build).
  • app_version() reads package metadata → _version.py → dev placeholder; static/version.json removed (now a build artifact, gitignored). /api/health reports the derived version.
  • Install sites pin SETUPTOOLS_SCM_PRETEND_VERSION from the release version so shallow CI clones / Docker (no .git) don't break: build/Dockerfile (--build-arg VERSION), make-runtime-pack.sh, make-portable.ps1.
  • make-app.sh defaults VERSION to git describe.
  • Desktop literals (Cargo.toml, package.json, tauri.conf.json) are now 0.0.0 placeholders stamped from the tag at build (Woodpecker prepare + make-scripts).
  • Update-check no longer nags dev/source builds (git-derived versions are ahead of the last release).

Version model: a clean tagged checkout reports the exact release (0.7.0a4); main between tags reports a dev version (0.7.0a5.dev3+g…). "Latest version" = the most recent tag.

Verification

  • 81 tests pass; ruff clean; node --check clean.
  • app_version() verified: dirty tree → 0.7.0a5.dev0+g0e84166…; uv.lock no longer pins a stale version.
  • Build-side (Docker --build-arg, Woodpecker, desktop packs) edited to feed the version but not runnable here — verify on a release build before tagging.

Deferred (not in this PR): #171 (CSP) and #172 (macOS ffmpeg checksum).

Closes #169
Closes #170
Closes #173

thcp added 5 commits June 2, 2026 12:15
#170 — Stored XSS via library folder names: folder.name was interpolated
raw into innerHTML in the folder render path. Escape it with the existing
esc() helper (catalog.js), matching the track render paths.

#173 — SoundCloud SSRF surface: drop the on.soundcloud.com share shortener
from the host allowlist (it redirects to arbitrary targets) and add a
yt-dlp extractor allowlist (allowed_extractors=[youtube, soundcloud]) so a
URL that slips past host validation can't invoke the generic extractor.

#169 — Version stuck at 0.6.0-alpha.2 for source/Docker/self-hosted: make
the version git-tag-derived via hatch-vcs (pyproject dynamic version,
app/_version.py build artifact). app_version() now reads package metadata
-> _version.py -> dev placeholder; static/version.json is removed (now a
build artifact, gitignored). Install sites pin SETUPTOOLS_SCM_PRETEND_VERSION
from the release version so shallow CI clones / Docker (no .git) don't break
(Dockerfile, make-runtime-pack.sh, make-portable.ps1). make-app.sh defaults
VERSION to `git describe`. Desktop version literals (Cargo.toml, package.json,
tauri.conf.json) are now 0.0.0 placeholders stamped from the tag at build.
The update-check no longer nags dev/source builds.

Tests: 81 passed; ruff clean; app_version derives correctly.
The hatch-vcs build hook writes app/_version.py during uv sync, and CI's
`ruff format --check app/` tripped on it (it's gitignored but present on
disk during lint). Add it to ruff's exclude list.
CI runs uv sync in every step, which builds the editable package and
triggers hatch-vcs/setuptools_scm. On Woodpecker's shallow, tagless clone
setuptools_scm raises ("unable to detect version"), failing the lint step
before ruff runs (and skipping the rest).

- Set SETUPTOOLS_SCM_PRETEND_VERSION=0.0.0 in the uv-based CI steps so the
  build never invokes git for the version (CI only lints/tests, never ships).
- Add hatch-vcs fallback-version as a second safety net for shallow source
  installs outside CI.

Verified: uv sync --frozen --all-extras succeeds with the env set.
Folder names now accept only letters (any language), digits, spaces, and a
small safe punctuation set (- _ ' & ( ) . ,). Names with markup or symbols
(e.g. the XSS probe, or ±!@£$%^&*()_+{:"|?><) are rejected on Save with an
inline message instead of being created. Complements the render-time escaping
from #170 by blocking such names at the source.
Bump the editor input maxlength from 48 to 100 and reject over-length names
on Save with an inline message (defensive, in case the cap is bypassed).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant