Files
Kim DaeHyun 4f2fdc4e05 fix: complete pre-release audit and Plasma tray overflow (#828)
* 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
2026-08-16 00:13:29 +09:00
..
2026-08-14 22:38:37 +09:00
2026-08-14 22:38:37 +09:00

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.