diff --git a/CHANGELOG.md b/CHANGELOG.md index aa1078b..c6e072f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ยท versioned wi - **Voice list rows no longer show the "Source unknown" badge** (it crowded the play buttons). The badge stays in the voice inspector, next to the Source & consent panel. ### Fixed +- **Magazine specs no longer touch the live settings.** The export-provenance checkboxes read and saved `/api/settings` on the real app (a run left the default off, failing the next one); the spec now mocks it. The hostile deep-link spec waits for the lazily loaded magazine module before calling the parser. - **Duplicate German i18n keys and dead frontend code.** Removed 14 shadowed duplicate keys in `i18n.js` (effective translations unchanged), the unreachable body of `audiobookShowPreview`, and two identical-branch ternaries. - **Security hardening (Sonar findings).** The Docker installer downloads `get-docker.sh` into a private `mkdtemp` dir (not a predictable `/tmp` path) and removes it afterwards; the OMDb poster lookup uses HTTPS; the fish.audio cache key marks MD5 as `usedforsecurity=False`. - **Background jobs could be garbage-collected mid-run.** Fire-and-forget `asyncio.create_task` calls (magazine, conversation, tts, stt, library, sources) now go through `core.tasks.spawn`, which keeps a strong reference until the task ends and logs failures by exception class only. diff --git a/tests/magazine.spec.js b/tests/magazine.spec.js index f2cf499..5bfc51e 100644 --- a/tests/magazine.spec.js +++ b/tests/magazine.spec.js @@ -122,6 +122,8 @@ async function mockBackend(page, { articleStatus = 'detected', hasAudio = false, await page.route('**/api/voices*', route => route.fulfill({ json: [{ id: 'smoke_voice', name: 'Smoke voice', enabled: true, tag: 'Magazine' }], })); + // The export-provenance default is read and saved through /api/settings; never let a spec reach the live one. + await page.route('**/api/settings', route => route.fulfill({ json: { export_provenance_default: true } })); } test.describe('Magazine reader', () => { @@ -1797,6 +1799,8 @@ test.describe('Share link and deep link into driving mode', () => { const bad = `/#s-magazine?doc=${DOC_ID}&article=%22%3E%3Cimg%20src%3Dx%20onerror%3Dwindow.__xss%3D1%3E&mode=drive`; await openLink(page, bad); await navTo(page, 's-magazine'); + // The magazine module loads lazily: wait for it, so the checks below run against the loaded parser. + await page.waitForFunction(() => typeof window.magParseDeepLink === 'function', null, { timeout: 15_000 }); await expect(page.locator('#mag-driving')).toBeHidden(); expect(await page.evaluate(() => window.__xss)).toBeUndefined(); const { parse } = await page.evaluate(() => ({ parse: [