fix(tools): support Tirith auto-install on Windows (#26044) - #26069
fix(tools): support Tirith auto-install on Windows (#26044)#26069spranab wants to merge 1 commit into
Conversation
Before this change, `_detect_target()` returned `None` for
`system == 'Windows'` because it only handled Darwin and Linux/Android.
That caused `_install_tirith` to bail out with the "unsupported_platform"
failure marker even though Tirith ships an
`x86_64-pc-windows-msvc.zip` release artifact — leaving Windows users
permanently on pattern-matching-only command scanning.
Three things had to move in lockstep, since the Windows release shape
differs from the POSIX one:
1. `_detect_target` adds a Windows branch returning
`x86_64-pc-windows-msvc`. aarch64-Windows returns `None` until
upstream Tirith adds that build.
2. `_install_tirith` selects `.zip` vs `.tar.gz` and `tirith.exe`
vs `tirith` via two small helpers (`_archive_extension`,
`_binary_name`). The Windows path extracts the binary via
`zipfile.ZipFile` with the same defence-in-depth filters as the
tar path (basename match, reject `..`, reject absolute paths).
3. `os.chmod` is skipped on Windows — Windows derives executability
from file extension + ACLs, not the POSIX user/group/other-execute
bits, so the previous `os.chmod(dest, ... | S_IXUSR | S_IXGRP | S_IXOTH)`
call would have been a no-op at best and a permissions-deny at worst.
All three `shutil.which("tirith")` and
`os.path.join(_hermes_bin_dir(), "tirith")` call sites are updated
to use `_binary_name()`, so user-installed-vs-auto-installed binary
resolution stays consistent across platforms.
Tests
-----
17 new test cases under `TestWindowsTargetDetection`,
`TestPlatformHelpers`, and `TestWindowsInstallFlow` cover:
- `_detect_target` returns `x86_64-pc-windows-msvc` for AMD64 and
x86_64 spellings; returns `None` for ARM64-Windows (until upstream
ships) and unsupported systems (regression-guarding the new branch).
- Helper functions `_binary_name` / `_archive_extension` /
`_is_windows_target` are tested in isolation for every supported
target triple.
- End-to-end install flow with a mocked downloader exercising the
Windows path: zip archive URL selected, `tirith.exe` written to
`<hermes_bin>/tirith.exe`, no `chmod` on the destination,
path-traversal entries rejected, missing-binary archive surfaces
`binary_not_in_archive`, corrupt zip surfaces `archive_extract_failed`.
Full file: 60 pre-existing tests still pass; 3 pre-existing failures
on Windows-local (Path.home() expansion quirks) are unchanged by this
patch. ruff + mypy (against tools/tirith_security.py specifically) at
the same baseline as upstream main.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for the cross-reference — agreed, #26068 is the right baseline for #26044 and #26069 is the weaker fix. The decisive gap: I only match (#23050 also seems to be an empty merge — 0 files / 0 commits on the PR record — so the assertion that base Windows support already landed isn't quite right; current Closing this PR. A few things in #26069 that may be worth pulling forward into #26068 (or as a small follow-up once it merges); happy to send any of them as a tightly-scoped PR against #26068's branch:
Apologies for the duplicate filing — I checked existing PRs against #26044 before opening but missed #26068 which was opened 16 minutes earlier (under a slightly different title). Will widen the pre-filing search next time. |
Summary
Fixes #26044. Tirith auto-install bailed out with
unsupported_platformon Windows because_detect_target()only handled Darwin and Linux/Android. Tirith publishes anx86_64-pc-windows-msvc.ziprelease artifact, so the binary is in fact available — Hermes just couldn't reach it. With this PR, Windows users (including MSYS and git-bash) get the same auto-install + cosign + SHA-256 flow every other platform already has.Why it's three changes, not one
The Windows release shape differs from the POSIX one in three ways, and a half-fix would leave a non-working install. So this PR moves all three in lockstep:
_detect_target()adds a Windows branch returningx86_64-pc-windows-msvc. aarch64-Windows returnsNoneuntil upstream Tirith ships that build (a single line to flip when it does)..zipcontainingtirith.exe; other platforms are.tar.gzcontainingtirith. Two small helpers (_archive_extension,_binary_name) keep the branching explicit and testable. The Windows extraction path useszipfile.ZipFilewith the same defence-in-depth filters as the existing tar path (basename match, reject.., reject absolute paths, fall back tobinary_not_in_archive/archive_extract_failedon bad input).os.chmodis skipped on Windows. Windows derives executability from file extension + ACLs, not the POSIX user/group/other-execute bits, so the existingos.chmod(dest, ... | S_IXUSR | S_IXGRP | S_IXOTH)would have been a no-op at best and a permissions-deny in some environments at worst.All three
shutil.which("tirith")andos.path.join(_hermes_bin_dir(), "tirith")call sites are updated to use_binary_name(), so user-installed-vs-auto-installed binary resolution stays consistent across platforms.Tests
17 new cases under
TestWindowsTargetDetection,TestPlatformHelpers, andTestWindowsInstallFlow:TestWindowsTargetDetection_detect_targetreturns the right triple for AMD64 + x86_64 spellings; refuses aarch64-Windows until upstream ships; doesn't accidentally match unrelated systems (regression-guard for the new branch)TestPlatformHelpers_binary_name,_archive_extension,_is_windows_targetin isolation across every supported target triple including aNone/ empty-string guardTestWindowsInstallFlowtirith.exewritten to<hermes_bin>/tirith.exe, nochmodon the destination, path-traversal entries rejected, missing-binary archive surfacesbinary_not_in_archive, corrupt zip surfacesarchive_extract_failedThe 3 failures are pre-existing
Path.home()expansion issues on Windows-local (TestHermesHomeIsolation::test_failure_marker_respects_hermes_home,TestHermesHomeIsolation::test_get_hermes_home_fallback,TestDiskFailureMarker::test_install_failed_recovers_from_hermes_bin). They fail identically on unmodified upstreammain, so this patch doesn't introduce them — confirmed by stashing the patch and re-running.The 1 mypy error (
Incompatible return value type (got "str | bool", expected "str")on the_INSTALL_FAILEDsentinel) is pre-existing onmain— same line, same message before this patch.Verification
tirith-x86_64-pc-windows-msvc.zip,checksums.txt,checksums.txt.sig,checksums.txt.pem— same cosign + checksum chain as the POSIX artifacts.unsupported_platformmarker onmain; this branch resolves it.TestWindowsInstallFlowexercise every branch of the new code instead.Fixes #26044