From 68acccbfc405c83604e9b7d2f2820bd3704511f1 Mon Sep 17 00:00:00 2001 From: "pullapprove5-fix[bot]" <4489445+pullapprove5-fix[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 22:14:04 +0000 Subject: [PATCH] Fix: Windows: downloaded mkcert binary saved without .exe extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reproduced the finding with a new unit test (plain-dev/tests/public/test_mkcert.py) that mocks platform.system() to \"Windows\" and drives MkcertManager.setup_mkcert() through its download path (stubbing the actual network download and CA-install subprocess calls to keep the test hermetic): before the fix, the resulting mkcert_bin path was the extensionless \"mkcert\", confirming the finding. Fixed plain-dev/plain/dev/mkcert.py by choosing \"mkcert.exe\" as the binary filename when platform.system() == \"Windows\" (else \"mkcert\"), mirroring the exact pattern already used in plain-tailwind/plain/tailwind/core.py and plain-code/plain/code/oxc.py for their own cached binaries. Re-ran the test after the fix and it passed. Ran the full plain-dev package test suite (146 tests, via `cd plain-dev/tests && uv run --isolated --package plain-dev --with 'psycopg[binary]' python -m pytest`, since scripts/test requires Docker/Postgres which isn't available in this sandbox) — all 146 passed, no regressions. Also ran `./scripts/fix plain-dev` (ruff + oxlint/oxfmt + prettier) with no issues. Committed the fix and test as a single commit (9b2f03c2f6). Note: uv wasn't preinstalled in this sandbox, so I installed it via `pip install --user uv` to run the checks — this is a sandbox-environment detail with no effect on the change itself. --- plain-dev/plain/dev/mkcert.py | 3 ++- plain-dev/tests/public/test_mkcert.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 plain-dev/tests/public/test_mkcert.py diff --git a/plain-dev/plain/dev/mkcert.py b/plain-dev/plain/dev/mkcert.py index 3c99913bb5..76bbe9ff48 100644 --- a/plain-dev/plain/dev/mkcert.py +++ b/plain-dev/plain/dev/mkcert.py @@ -27,7 +27,8 @@ def setup_mkcert(self, *, force_reinstall: bool = False) -> None: # mkcert not found system-wide, download to the machine-level cache install_path = PLAIN_CACHE_PATH / "mkcert" install_path.mkdir(parents=True, exist_ok=True) - binary_path = install_path / "mkcert" + binary_name = "mkcert.exe" if platform.system() == "Windows" else "mkcert" + binary_path = install_path / binary_name if force_reinstall and binary_path.exists(): click.secho("Removing existing mkcert binary...", bold=True) diff --git a/plain-dev/tests/public/test_mkcert.py b/plain-dev/tests/public/test_mkcert.py new file mode 100644 index 0000000000..575cf76626 --- /dev/null +++ b/plain-dev/tests/public/test_mkcert.py @@ -0,0 +1,23 @@ +import platform + +from plain.dev.mkcert import MkcertManager + + +def test_windows_binary_gets_exe_extension(tmp_path, monkeypatch): + """On Windows, the downloaded mkcert binary must be named with a .exe + extension, or CreateProcess can't launch it via subprocess.run.""" + monkeypatch.setattr("plain.dev.mkcert.PLAIN_CACHE_PATH", tmp_path) + monkeypatch.setattr(platform, "system", lambda: "Windows") + monkeypatch.setattr("plain.dev.mkcert.shutil.which", lambda name: None) + + def fake_download(self, dest): + dest.write_bytes(b"fake binary") + + monkeypatch.setattr(MkcertManager, "_download_mkcert", fake_download) + monkeypatch.setattr(MkcertManager, "install_ca", lambda self: None) + monkeypatch.setattr(MkcertManager, "_ca_files_exist", lambda self: True) + + manager = MkcertManager() + manager.setup_mkcert() + + assert manager.mkcert_bin.endswith(".exe")