Skip to content

LOC-7228: Relax psutil upper bound to allow psutil 7.x - #63

Open
vivianludrick wants to merge 1 commit into
masterfrom
LOC-7228-relax-psutil-upper-bound
Open

LOC-7228: Relax psutil upper bound to allow psutil 7.x#63
vivianludrick wants to merge 1 commit into
masterfrom
LOC-7228-relax-psutil-upper-bound

Conversation

@vivianludrick

@vivianludrick vivianludrick commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Relax the psutil runtime dependency constraint from psutil>=5.6.6,<7 to psutil>=5.6.6
  • Bump package version to 1.2.16 for release

Context

LOC-7228 — a customer installing the BrowserStack Python SDK hit a dependency conflict:

browserstack-local 1.2.15 has requirement psutil<7,>=5.6.6, but you have psutil 7.2.2.

psutil is a runtime dependency (declared in install_requires, imported in browserstack/local.py), not a dev dependency. The upper bound is removed entirely (rather than bumped to <8) so this conflict doesn't recur on the next psutil major release, given the minimal API surface (see below).

The upper bound was added as a response for a CVE raised in LOC-6720. CVE-2019-18874 affected range (NVD + OSV/GHSA-qfc5-mcwq-26q8): psutil through 5.6.5 has a double free from refcount mishandling; the affected range is [0, 5.6.6) with fixed = 5.6.6. The mitigation is entirely the >=5.6.6 floor. Newer versions, including all of 6.x and 7.x — are fixes, not risks, for this CVE.

Verification

1. API surface auditpsutil.pid_exists() (browserstack/local.py:131, inside isRunning()) is the only psutil API used anywhere in the package, including tests.

2. psutil 7.x changelog review (psutil.io/changelog) — 7.0.0 dropped Python 2.7 and removed only Process.memory_info_ex() (deprecated since 4.0.0, unused here). pid_exists() was not removed or signature-changed in any 7.x release. One behavior fix: on Windows, pid_exists() now returns the correct answer under ERROR_ACCESS_DENIED instead of disagreeing with Process. For our usage (checking the daemonized binary's pid, same user) this is neutral-to-beneficial — the new behavior is the correct answer for isRunning().

3. Legacy Python safety — psutil 7.x declares requires_python >= 3.6 on PyPI (verified via PyPI JSON API), so pip on Python 2.7/3.5 automatically resolves to psutil 6.1.x; removing our upper bound cannot break those installs.

4. Live install + functional test — clean venv (Python 3.11), pip install psutil==7.2.2 + this package from source:

  • pip checkNo broken requirements found (the exact failure from the ticket, resolved)
  • isRunning() exercised against a live pid / killed pid / missing pid attr → all correct under psutil 7.2.2

5. Wheel coverage — psutil 7.2.2 ships prebuilt wheels for win_amd64, win_arm64, macOS, manylinux, musllinux.

Known edge case

psutil dropped 32-bit Windows (win32) wheels after 7.0.0 (6.1.1 and 7.0.0 have them; 7.2.2 does not). A user on 32-bit Windows Python without MSVC build tools would fail to build psutil from sdist on a fresh install. Judged acceptable: 32-bit Python is rare in 2026, the SDK ecosystem already pulls psutil 7.x (which is what caused this ticket), and environment markers cannot reliably detect interpreter bitness to special-case it.

browserstack-local 1.2.15 pinned psutil>=5.6.6,<7, which conflicts with
environments that already have psutil 7.x installed (e.g. alongside the
BrowserStack SDK). The only psutil API used is psutil.pid_exists(),
which is unchanged in psutil 7, so the upper bound is unnecessary.

Fixes LOC-7228

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vivianludrick
vivianludrick requested a review from a team as a code owner July 30, 2026 18:19

@07souravkunda 07souravkunda left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the constraint relaxation and re-checked the claims in the description against primary sources — they all hold. The <7 cap came in with the LOC-6720 commit (b5bb4f7) alongside the >=5.6.6 floor; OSV lists exactly one psutil advisory ever (CVE-2019-18874, introduced: 0, fixed: 5.6.6) with nothing affecting 6.x or 7.x, so the floor is the entire mitigation and removing the ceiling reintroduces no known vulnerability; pid_exists() at local.py:131 is the only psutil API in the package or its tests; and 7.2.2 ships cp36-abi3 wheels, so there is no Python 3.6/3.7 sdist regression (the aarch64 wheel also still carries manylinux_2_17, so no glibc floor bump). 1.2.16 is the right version — PyPI latest is 1.2.15 and setup.py is the only place a version is declared.

Also cross-checked the consumer side: browserstack_sdk requires bare psutil plus browserstack-local>=1.2.5, which confirms the cap came solely from this package and means a fresh SDK install picks up 1.2.16 with no SDK release needed.

One non-blocking comment inline: the documented edge case covers win32 but misses 32-bit Linux (i686), which lost wheels on the same boundary and is a platform local_binary.py explicitly branches for. Not a merge blocker — fine to land with the note extended, or with the cap scoped to 32-bit via an environment marker.

Comment thread setup.py
classifiers = [],
install_requires=[
'psutil>=5.6.6,<7',
'psutil>=5.6.6',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Known edge case" section covers 32-bit Windows, but psutil dropped 32-bit Linux (i686) wheels on the same boundary — and 32-bit Linux is a platform this package explicitly serves.

Evidence — wheel platform tags on PyPI:

psutil linux i686 wheel win32 wheel
6.1.1 yes yes
7.0.0 yes yes
7.2.2 no no

browserstack/local_binary.py:17,31-34 computes is_64bits = sys.maxsize > 2**32 and downloads BrowserStackLocal-linux-ia32 for 32-bit interpreters, so 32-bit Linux is a first-class target here. Windows, by contrast, has no bitness branch at all (local_binary.py:36 → a single BrowserStackLocal.exe). With the cap removed, a fresh install on a 32-bit Linux interpreter resolves psutil 7.2.2 and must compile it from sdist (gcc + Python headers) where 6.1.1/7.0.0 supplied a wheel — a minimal CI image without a toolchain fails the install outright.

Worth adding the flip side to the description as well: 7.2.2 gains musllinux wheels (x86_64 + aarch64) that 6.1.1 lacked entirely, so Alpine users (local_binary.py:26BrowserStackLocal-alpine) go from an sdist build to a wheel. Net wheel coverage improves for a supported platform.

Fix — either extend the documented edge case to win32 + linux i686 and accept it knowingly, or scope the cap to 32-bit so wheel coverage is preserved everywhere:

install_requires=[
    'psutil>=5.6.6',
    'psutil<7; platform_machine in "i686 i386 x86"',
]

On "environment markers cannot reliably detect interpreter bitness" — markers do expose platform_machine, which pip evaluates as i686 on 32-bit Linux and x86 for 32-bit CPython on Windows (a WOW64 process reports PROCESSOR_ARCHITECTURE=x86). I haven't tested that resolution myself, and platform_machine reflects the OS/WOW64 view rather than sys.maxsize, so worth a pip install --dry-run --platform manylinux2014_i686 check before relying on it.

Question for author: was 32-bit Linux considered alongside win32, or did the wheel audit look only at the Windows set (the LOC-7228 customer is on Windows)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants