Commit Graph
5 Commits
Author SHA1 Message Date
Paolo Antinori f669687ed1 feat(backend): trust a local network/proxy via OMNIVOICE_TRUSTED_NETWORKS (#1170)
Self-hosting behind a reverse proxy or on a LAN used to force a blunt choice:
OMNIVOICE_SERVER_MODE (trust every non-loopback source) or the API-key/PIN gates
— which a proxy that strips the Authorization header breaks for browser clients
entirely.

Add OMNIVOICE_TRUSTED_NETWORKS (comma-separated CIDRs) whose addresses are
treated as trusted by the CONSUMPTION gates (PIN/API-key middleware, dictation
WebSocket) via is_local_host — a LAN/proxy client is exempted from consumption
auth. Admin routes (require_loopback → /system/set-env, /api/settings/*) stay
true-loopback-only (is_loopback, not is_local_host) to preserve the two-tier
privilege model: consumption trust ≠ admin trust (RCE-class surface). Opt-in,
default empty → zero behavior change. The granular companion to server-mode (#261).

Tests: is_loopback / is_local_host / require_loopback contract for trusted CIDRs,
adjacent subnets, malformed entries, the two-tier split (trusted-network rejected
by the admin gate), and the default (no-trust) case. Docs + CHANGELOG.
2026-07-17 17:33:18 +02:00
3f62471bad test: pay down export-router test debt + kill two test-order pollution classes (#1081)
Four pieces of test debt, root-caused and hardened:

1. exports.py test coverage (was: zero dedicated tests): new
   tests/test_exports_api.py (26 tests) covering /export, /export/record,
   /export/history, /export/reveal — happy paths, traversal/containment
   guards (incl. symlink escape), destination validation, error mapping,
   and the mp4 watermark-overlay branch with its plain-copy fallback.
   Two real bugs found and fixed in the router:
   - _safe_destination checked isabs() on realpath()'s output, which is
     always absolute — dead check; a relative destination silently exported
     to a cwd-dependent location instead of the documented 400.
   - _safe_source let "." / ".." through the basename guard (caught only
     later by realpath containment as a confusing 404); now 400 up front.

2. CI-Linux fp16 default-dtype leak (test_prefers_vocals_over_mix,
   test_final_dub_track_and_seg_wav_are_watermarked): not reproducible on
   macOS — instrumenting torch.set_default_dtype across both tests records
   zero non-fp32 sets locally. Both tests now carry an opt-in
   torch_dtype_isolation fixture (save/restore, so the leak can never
   spread), and the conftest guard is demoted to pure insurance. A cheap
   permanent recorder wraps torch.set_default_dtype /
   set_default_tensor_type once torch appears and captures the setter's
   stack only on a non-fp32 set; both fixtures print that stack when they
   fire, so the next CI occurrence names the exact culprit call chain.

3. Test-order pollution (both reported combos): root cause was
   collection-time sys.modules stubbing in backend/tests — seven modules
   installed bare ModuleType stubs for core.config (and test_capture_ws.py
   for services.model_manager/asr_backend/ffmpeg_utils, now all lazily
   imported by the router anyway). pytest imports test modules during
   collection, so the stubs leaked process-wide before any test ran:
   - combo (a): monkeypatch.setattr("core.config.OUTPUTS_DIR", ...) in
     test_longform_e2e died with AttributeError (core never gets a .config
     attribute when the import is satisfied straight from sys.modules).
   - combo (b): test_router_smoke's `from main import app` died with
     ImportError: cannot import name 'find_ffmpeg' (unknown location).
   Fix at source: new backend/tests/conftest.py sets a hermetic
   OMNIVOICE_DATA_DIR (mirroring tests/conftest.py, #878) and the real
   core.config is imported everywhere — zero sys.modules surgery. New
   backend/tests/test_no_module_stubs.py guards the whole class (verified
   fail-before/pass-after against the old stub). Stale rationale comments
   in pyproject.toml and ci.yml updated to match.

4. batched_tts.py TODO(#312): investigated, comment corrected only —
   #312 is closed (the live routes are engine-aware); this module has zero
   call sites and stays an unintegrated experiment. See PR notes.

Full tests/ suite: 2796 passed. backend/tests standalone: 130 passed.
Both pollution combos re-run green in the reported orderings.

Co-authored-by: mergetest <test@local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 23:10:35 +05:30
Palash DebnathandClaude Opus 4.8 47729057bd chore(lint): remove unused imports + variables (ruff F401/F841) (#210)
Autofixes the genuine lint behind the CodeQL py/unused-import and
py/unused-local-variable note-level alerts — actually removing the dead
code rather than dismissing it. 68 safe fixes via 'ruff check --select
F401,F841 --fix' across 29 backend files (dead stdlib/symbol imports like
io/sys/json/torch/typing.Optional and unused locals). Only ruff's safe
fixes applied — the 9 'unsafe' fixes and the audio_dsp numpy availability
import were left untouched.

Not touched: empty-except (needs per-site judgement, not autofixable);
frontend js/unused-local-variable (eslint no-unused-vars has no autofix);
the loopback-low-risk path/log/stack-trace alerts (real, left visible).

Verified: full tests/ suite unchanged at 601 passed (the 2 test_supertonic3
failures are pre-existing on main, local .venv state, green in CI).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 07:53:06 +05:30
Palash Debnath 651e63b7e9 P0 wave-1: security + correctness + Phase 2 foundation (#88)
P0 security + correctness fixes plus Phase 2 foundation work. 7 atomic commits, all CI green (Smoke + Tauri shell on macOS/Win/Linux + Tests).

Code commits:
- 92f716e: P0 security — loopback guard on /ws/transcribe before accept()
- fb52140: P0 dub — atomic WAV writes (closes #48 partial; Phase 2 plan 02-02 covers remaining sites)
- 9545640: P0 supply-chain — pin BtbN ffmpeg URL via FFMPEG_BTBN_VERSION
- e414665: P0 security — remove torch.load monkey-patch in asr_backend
- 6b49290: docs — Phase 4 plan <action> blocks on checkpoint tasks
- e764fdb: Phase 2 prep — TTSBackend.unload() foundation
- 71c10dc: test — fix capture_ws TestClient host for loopback guard

243 pytest passing, 0 failures. All 18 phase plans now validate.
2026-05-19 21:11:25 +05:30
Palash Debnath 8d11e19494 feat: dictation maturity + batch TTS pipeline + tests (#32)
Global Hotkey:
- Register ⌘+⇧+Space system-wide via tauri-plugin-global-shortcut
- Shows/focuses window and emits tray-dictate event from any app

Auto-Paste:
- enigo crate simulates ⌘V/Ctrl+V after transcription
- Text auto-pastes into whatever app was active before dictation

Streaming ASR:
- WebSocket endpoint /ws/transcribe for live partial transcription
- 2s buffer interval, configurable via OMNIVOICE_STREAM_INTERVAL
- CaptureButton streams audio chunks, shows italic partial text
- Falls back to HTTP POST if WebSocket unavailable

Batch TTS Pipeline:
- Replace stub worker with full pipeline:
  extract → transcribe → translate → generate → mix → export
- Per-job progress tracking (stage, percent, current_lang, segment)
- GoogleTranslator integration via deep_translator
- Download endpoint GET /batch/download/{id}/{lang}
- BatchQueue UI rewritten: progress bars, cancel/delete, downloads
- Type-safe API client (api/batch.ts)

Tests:
- 23 tests for batch endpoints + streaming ASR helpers
- Lightweight fixtures that stub GPU deps

UX (earlier sessions):
- Dual-mode ASR (Turbo MLX + WhisperX Accurate)
- Enhanced download progress (speed, ETA, bytes)
- Status bar black flash fix
- Cold-start model preloading
- Full accessibility audit (ARIA, focus-visible)
- Compact UI layout improvements
- README updated with new features
2026-04-28 18:54:26 +05:30