Repository navigation
Conversation
…uses processFlagValue() returned the first occurrence of a switch, but Chromium keeps the last. Launcher wrappers can put the user's own flags before the arguments ego passes; Arch's google-chrome-stable, for one, inserts ~/.config/chrome-flags.conf ahead of "$@". - A second --user-data-dir made the managed browser stop matching its profile: browserStatus() reported it not running, and the next ensureBrowser() refused to launch because the profile lock owner "is not a managed Ego Lite browser". - A second --remote-debugging-port made browserStatus() report it not running, made ensureBrowser() without a browser.json kill it and launch another, and made stopBrowser() signal it instead of closing it over CDP. - unsafeBrowserLaunchFlags() judged a repeated --remote-debugging-address by its first value; any non-loopback value now makes the browser unsafe. processFlagValue() and processHasArg() also searched the space-joined argv when argv was tokenized, so "--note=x --user-data-dir=<profile>" or a --class marker inside another argument's value counted as the switch. That scan now runs only on the single-string title Chromium writes into /proc/<pid>/cmdline, where a flag has to start a word. Chromium joins that title without quoting, so quote characters stay part of a value and a profile path with an apostrophe still matches. As in Chromium, no switch counts after a bare "--". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
src/chrome.mjsdecides which running process is the managed browser by reading its switches. It read the first occurrence of a switch where Chromium uses the last, and it found switches inside other arguments' values. A launcher that prepends flags therefore made ego disown its own browser, then refuse to start a new one or replace the running one.Related issue
None: issues are disabled on this repository.
Changes
The last occurrence of a switch wins
Launcher wrappers can put the user's own flags before the arguments ego passes. The
google-chrome-stablewrapper in Arch Linux'sgoogle-chromepackage, for example, inserts the contents of$XDG_CONFIG_HOME/chrome-flags.confahead of"$@". The managed browser's command line then carries a switch twice. Chromium keeps the last value (InsertOrAssigninCommandLine::AppendSwitchNative,base/command_line.cc);processFlagValue()returned the first. As a result:--user-data-dir:browserStatus()reported the managed browser as not running, and the nextensureBrowser()found no reusable browser, tried to launch one and refused, because the profile's lock owner, its own browser, "is not a managed Ego Lite browser".--remote-debugging-port:browserStatus()reported the browser as not running;ensureBrowser()without abrowser.json(for example under another state root) killed it and launched a new one;stopBrowser()could not close it over CDP and signalled it instead.unsafeBrowserLaunchFlags()judged--remote-debugging-address=127.0.0.1 … --remote-debugging-address=0.0.0.0safe by its first value, although Chrome listens on0.0.0.0.processFlagValues()now returns every occurrence. Ownership checks use the last one, and the unsafe-launch check rejects the browser when any value is not a loopback address. Like Chromium, which stops reading switches at a bare--(AppendSwitchesAndArguments), nothing after--counts.Flag text inside another argument is not a flag
For a tokenized argv,
processFlagValue()andprocessHasArg()also searched the space-joined arguments. An argument such as--note=x --user-data-dir=<profile>or--note=x --class=ego-lite-linuxthus counted as the switch it contains. Joined-text scanning now runs only on the single-string title that Chromium writes into/proc/<pid>/cmdline, where argument boundaries are already lost, and there a flag has to start a word.SetProcessTitleFromCommandLine()(base/process/set_process_title.cc) builds that title by joining argv with spaces and no quoting, so quote characters are treated as part of a value: a profile path containing an apostrophe still matches.Reproduction
With a real headless Chrome started through a wrapper that prepends its own switches, and
EGO_LINUX_CHROMEpointing at the wrapper, the state and profile in a scratch directory:/tmp/elsewhereexists; it stands in for the user's normal profile. CallingensureBrowser({ headless: true }), thenbrowserStatus(), thenensureBrowser()again:mainensureBrowser()browserStatus()running: falserunning: trueensureBrowser()Profile lock owner <pid> is not a managed Ego Lite browser; refusing to edit or unlock <profile>launched: false)With a wrapper that prepends only
--remote-debugging-port=9, deletingbrowser.jsonafter the first launch:mainbrowserStatus()running: falserunning: trueensureBrowser()stopBrowser()exit_type: SessionEndedexit_type: NormalVerification
npm testinpackage/ego-linux, run in a clean environment as in CI: no inheritedEGO_*variables, and the XDG directories in a scratch directory.mainnpm testtest/process-flags.test.mjs(7 new tests) againstmain'schrome.mjsreapOrphanedBrowsers()every 20 msprettier --checkon the changed files¹
switches after a bare -- do not countpasses onmain, which reads the first occurrence; it guards the last-occurrence rule.The new tests use stand-in processes and a local HTTP endpoint, not a real browser. Each stand-in's command line is read back before any assertion, so a failed process query cannot make a negative test pass. Their profile directories exist, so a parallel suite's machine-wide
reapOrphanedBrowsers()leaves them alone. On Windows, where settingprocess.titledoes not change the command line, the rewritten-title test is skipped and the--test checks only the tokenized form; Windows argv comes fromsplitCommandLine(). The tests have not been run on Windows locally.Impact
No public helper change. This affects which running browser ego-linux treats as its own when it reuses, reports on, stops or reaps a browser.
🤖 Generated with Claude Code