Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/Semgrep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:

container:
# A Docker image with Semgrep installed. Do not change this.
image: returntocorp/semgrep
image: returntocorp/semgrep@sha256:9349edbadf90c3f3c0c3f55867625354e89680e6fa10d9034042af52fdb0e0d0
Comment thread
rounak610 marked this conversation as resolved.

# Skip any PR created by dependabot to avoid permission issues:
if: (github.actor != 'dependabot[bot]')
Expand Down
23 changes: 20 additions & 3 deletions browserstack/local.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import subprocess, os, time, json,logging
import subprocess, os, time, json, logging, re
import psutil

from browserstack.local_binary import LocalBinary
Expand Down Expand Up @@ -70,7 +70,16 @@ def start(self, **kwargs):
del self.options['key']

if 'binarypath' in self.options:
self.binary_path = self.options['binarypath']
candidate = os.path.realpath(self.options['binarypath'])
if not os.path.isfile(candidate):
raise BrowserStackLocalError('binarypath does not point to a file')
try:
version_output = subprocess.check_output([candidate, '--version'], timeout=10).decode('utf-8')
except (subprocess.SubprocessError, OSError) as e:
raise BrowserStackLocalError('binarypath failed verification: {}'.format(e))
if not re.match(LocalBinary.VERSION_REGEX, version_output):
raise BrowserStackLocalError('binarypath failed verification')
self.binary_path = candidate
del self.options['binarypath']
else:
l = LocalBinary(self.key)
Expand All @@ -90,10 +99,18 @@ def start(self, **kwargs):
if 'source' in self.options:
del self.options['source']

logfile_dir = os.path.dirname(self.local_logfile_path)
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.

This block truncates self.local_logfile_path after subprocess.Popen + communicate() (lines 102-103). By that point the binary has already written its startup output (the JSON ack, plus anything before backgrounding) to the same file — the truncation wipes it. Users debugging "why didn't my tunnel start" lose the binary's startup messages.

The truncation appears intended to clear stale output from a prior run — which it can't do here because by the time it runs, the current daemon has already written.

This ordering is pre-existing (master had the same shape with os.system), but since the PR is already editing these lines, this is the natural moment to fix it.

Suggested fix: move the truncation up — right after local_logfile_path is finalized (around line 94), before Popen. That way the file starts empty and the daemon's writes are preserved.

Question: is the post-Popen position load-bearing for some reason? If not, recommend moving it up.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed

if logfile_dir:
os.makedirs(logfile_dir, exist_ok=True)
try:
with open(self.local_logfile_path, 'w') as f:
Comment thread
rounak610 marked this conversation as resolved.
f.write('')
except OSError as e:
raise BrowserStackLocalError('Unable to open logfile: {}'.format(e))

self.proc = subprocess.Popen(self._generate_cmd(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = self.proc.communicate()

os.system('echo "" > "'+ self.local_logfile_path +'"')
try:
if out:
output_string = out.decode()
Expand Down
4 changes: 2 additions & 2 deletions browserstack/local_binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from urllib2 import urlopen, Request

class LocalBinary:
VERSION_REGEX = r"BrowserStack Local version \d+\.\d+"
_version = None

def __init__(self, key, error_object=None):
Expand Down Expand Up @@ -159,8 +160,7 @@ def read_chunk(chunk_size):
def __verify_binary(self,path):
try:
binary_response = subprocess.check_output([path,"--version"]).decode("utf-8")
pattern = re.compile("BrowserStack Local version \d+\.\d+")
return bool(pattern.match(binary_response))
return bool(re.match(LocalBinary.VERSION_REGEX, binary_response))
except:
return False

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
keywords = ['BrowserStack', 'Local', 'selenium', 'testing'],
classifiers = [],
install_requires=[
'psutil',
'psutil>=5.6.6,<7',
],
)

Loading