4f2fdc4e05
* fix(install): eject media after setup (#810) * test: close test-coverage gaps and add parallel runs + CI coverage gate Measure and then close the suite's coverage gaps. Overall statement coverage goes 56.7% -> 88.9%; every package is now >=80% and no module is under 70%. - Add 18 new test files and extend 34 existing ones (+1158 tests, 2379 -> 3537) - gui/ 28% -> 92%: launcher, settings, library, maintenance, logs, info, dashboard, pod, header, nav, license, workers, ring gauge, deleted-apps - desktop/tray.py 7% -> 90% via a headless offscreen run_tray() harness - core/ and cli/ gaps: pod, setup_cmd, main, app, migrate, doctor, config, disguise, usbredir, disk, daemon, stats, checks, rdp, discovery, updates, pod lifecycle, storage_migration, guest_sync, guest_disk, deps_quickcheck - backend/ 52% -> 91%, display/ 60% -> 91%, setup_wizard/ 54% -> 94%, reverse_open/ 77% -> 84% (lifecycle daemon control, icons) - Fix tests that previously blocked for minutes on real podman / FreeRDP by stubbing the guest-apply chain, the pod-status probe, the agent-settle poll, and the discovery/transport retry backoffs (29.5 min -> ~16 s parallel) - Add pytest-xdist and pytest-cov to the dev extra; run the suite with -n auto - Add a CI coverage job (installs [all] so Qt-gated tests execute) with a ratcheted --cov-fail-under=88 floor No production code changed; tests/ and CI/config only. * docs: refresh stale facts across user and contributor docs README: - Compress the Status block from a ~7.4 KB dump of every release note into 5 current highlights with a link to the CHANGELOG; add a table of contents. - Update the test badge from 1800+ to 3500+ (suite collects 3543). - Keep the Beta status (the pyproject classifier reading Pre-Alpha is the stale one, not the README). USAGE / FEATURES / INSTALL / ARCHITECTURE / COMPARISON (+ Korean mirrors): - Correct command surface (deprecated info/check aliases still work; install status/resume are placeholders; provision retries are 5 not 2). - Correct defaults: Start-Menu-only discovery, max_sessions 25, 6 GB RAM, home_share, WPX-User, idle pause/stop actions, pinned image. - Remove the deleted USB drive-letter mapper; document the \\tsclient\media share and usbredir behavior. - Update the Python matrix to 3.9-3.14 and document the pytest -n auto parallel run plus the CI coverage gate. - Verify every documented winpodx command against argparse; drop claims of capabilities that don't exist (e.g. PyPI publication) and qualify over-absolute comparison claims. CONTRIBUTING: add -n auto + coverage commands and the verify_versions step to the PR checklist; correct the Python matrix. Design docs: only present-tense claims that drifted (LIFECYCLE install/migrate flow, GUEST_SYNC commands); historical proposals and dated reviews unchanged. * fix(reverse-open): confine guest C: paths to the mount root guest_win_path_to_host() rejected '..' components but then joined the remaining parts lexically, and the listener spawned the result after a bare exists() check. A compromised guest can plant a symlink / reparse point in its own C: tree, so a path that looks contained resolves outside the gvfs mount and the host app is handed an arbitrary host file readable by the Linux user. Resolve both the candidate and the mount root and refuse anything that is not under the root, matching the containment rule the sibling \\tsclient route already enforces in reverse_open.paths. Found during the pre-release security audit. * docs(web): correct site facts and un-hide the README image from the sdist web/: version v0.9.1 -> v0.10.4 across the pages and all seven locale catalogs, config path ~/.config/winpodx.toml -> ~/.config/winpodx/winpodx.toml, screenshot caption 'Performance Monitor' -> 'Task Manager / Dashboard', replaced the 'anything that runs on Windows' claim with accurate wording about GPU/3D limits, and added the two shipped features the page was missing (winpodx launch, bare-metal disguise). Regenerated translations.js; all seven catalogs keep 221-key parity. .gitignore: anchor the demo.png rule to the repo root. A bare pattern matches at every depth, which hid the tracked docs/images/demo.png from the sdist (hatch honours .gitignore), so the source distribution shipped a README with a missing image. * docs(legal): correct third-party attribution for the current artifacts THIRD_PARTY_LICENSES.md described the pre-0.6.0 Fat AppImage: it claimed the release bundles the whole podman stack and that PySide6 is never redistributed. The shipped artifact has been the Thin AppImage since 0.6.0 — it bundles Python, Qt/PySide6, Pillow, cairosvg, pyxdg and FreeRDP/libwinpr, and does NOT bundle podman/podman-compose/conmon/crun/netavark/slirp4netns/passt. Rewrite that section, keep the retained license directories labelled as provenance for the old artifact, and record the known gap where bundle-system-bins.sh copies ldd-resolved .so files whose licenses are not collected per-library. Also: - Add the reverse-open extra (Pillow, cairosvg, pyxdg) to the optional table and pytest-xdist / pytest-cov / Pillow to the dev table. - Attribute the crates statically linked into the shipped reverse-open shim (getrandom, cfg-if; both MIT OR Apache-2.0), and note that winresource and its toml/serde deps are build-time only. Same stanza added to debian/copyright. - Add the CC BY 4.0 licence statement the Contributor Covenant requires to CODE_OF_CONDUCT.md and its Korean mirror. Found during the pre-release legal audit. No licence incompatibility was found: no GPL component is redistributed by any WinPodX artifact. * fix(reverse-open): re-check the pinned inode immediately before spawn safe_open_unc() validates against an O_PATH FD, but the listener hands the child safe.real_path so D-Bus-handoff apps (Firefox, LibreOffice, Chromium) keep working — those forward the path to a singleton that never inherits our FD table. That means the child reopens BY NAME, which reintroduces the swap the FD was meant to prevent: the audit reproduced renaming the validated parent away and dropping a symlink in its place, after which the spawned app opened the attacker's target. Retain the validated st_dev/st_ino on SafeFile and add assert_unchanged(), which reopens real_path with O_PATH|O_NOFOLLOW and refuses the spawn unless the device/inode still match the pinned FD. The listener calls it immediately before _spawn. Holding the original FD keeps the validated inode alive so its number cannot be recycled during the check. This is best-effort race DETECTION, not a TOCTOU-safe handoff, and the comments now say so: an attacker who wins the much narrower window between the check and the app's own open() is still unobserved. Closing it outright needs an FD-backed stable pathname (XDG Documents portal), tracked separately. The old comments claimed 'TOCTOU isn't in scope: user is acting on their own files' and that the FD made later swaps harmless. Both were wrong for this package's stated hostile-guest threat model; corrected in listener.py and the paths.py module docstring. Found during the pre-release security audit. * fix(tray): paginate long app menus on Plasma * fix(reverse-open): pin guest paths before spawn * docs(legal): correct shim dependency provenance * docs(ko): correct session and test counts * docs(ko): qualify discovery and compatibility claims * docs(ko): correct configuration example * fix(backend): normalize inspect timestamp fractions * ci: install EGL runtime for coverage tests * docs(ko): sync remaining feature caveats
docs/
User-facing documentation. Engineering / internal design notes live under design/.
Most documents have an English original and a Korean (.ko.md) mirror linked from the toggle at the top of each page. The repo-root README.md, CHANGELOG.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, SECURITY.md, and THIRD_PARTY_LICENSES.md are the English canonical copies; the corresponding .ko.md files in this folder are their Korean mirrors.
Index
| Topic | English | 한국어 |
|---|---|---|
| Quick install | INSTALL.md | INSTALL.ko.md |
| Day-to-day usage | USAGE.md | USAGE.ko.md |
| Feature list | FEATURES.md | FEATURES.ko.md |
| How it's put together | ARCHITECTURE.md | ARCHITECTURE.ko.md |
| vs. winapps, etc. | COMPARISON.md | COMPARISON.ko.md |
| README mirror | — | README.ko.md |
| Changelog mirror | — | CHANGELOG.ko.md |
| Code of conduct mirror | — | CODE_OF_CONDUCT.ko.md |
| Contributing mirror | — | CONTRIBUTING.ko.md |
| Security mirror | — | SECURITY.ko.md |
Screenshots and diagrams referenced from the docs above live in images/.
Engineering docs
For design specs, roadmaps, reference docs (lifecycle, transport ABC), and security reviews, see design/ and design/README.md.