Open Bug 1755140 Opened 2 years ago Updated 2 months ago

When Firefox is installed via Flatpak it fails to access the temporary profile folder

Categories

(Testing :: geckodriver, defect, P3)

defect

Tracking

(Not tracked)

People

(Reporter: yellowhat46, Unassigned, NeedInfo)

References

(Blocks 1 open bug)

Details

Attachments

(1 obsolete file)

User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) QtWebEngine/5.15.2 Chrome/87.0.4280.144 Safari/537.36

Steps to reproduce:

Hi,
I would like to use selenium against the flatpak version of Firefox (flatpak install -y flathub org.mozilla.firefox).

Consider the following example code:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.binary_location = "/var/lib/flatpak/exports/bin/org.mozilla.firefox"
options.add_argument("--marionette")
options.add_argument("--profile /home/vasco/.mozilla")
options.add_argument("--private")

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()

I have opened a bug on selenium (https://github.com/SeleniumHQ/selenium/issues/10283), maybe the remote code is not packaged?

My user agent:

Mozilla/5.0 (X11; Linux x86_64; rv:97.0) Gecko/20100101 Firefox/97.0

Thanks

Actual results:

The firefox window open but does not open google.com

Expected results:

Load the google.com page and exit.

The Bugbug bot thinks this bug should belong to the 'Core::Widget: Gtk' component, and is moving the bug to that component. Please revert this change in case you think the bot is wrong.

Component: Untriaged → Widget: Gtk
Product: Firefox → Core

yellowhat46 can you please try to get a trace log created and attached here? It's not clear to me what the failure is at all and such a log can really help. Thanks.

Flags: needinfo?(yellowhat46)
Attachment #9387472 - Attachment is obsolete: true

Hi,
If I try the following:

python -m venv /tmp/env
source /tmp/env/bin/activate
pip install --no-cache selenium webdriver-manager
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"
options.add_argument("--marionette")
options.add_argument("--profile /home/vasco/.mozilla")
options.add_argument("--private")

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()

If I leave options.add_argument("--marionette") , I get the error:

    with webdriver.Firefox(options=options) as driver:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py", line 69, in __init__
    super().__init__(command_executor=executor, options=options)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 208, in __init__
    self.start_session(capabilities)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 292, in start_session
    response = self.execute(Command.NEW_SESSION, caps)["value"]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 347, in execute
    self.error_handler.check_response(response)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/errorhandler.py", line 229, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.InvalidArgumentException: Message: Argument --marionette can't be set via capabilities

If I remove options.add_argument("--marionette") , a new window appears in private mode but does not load google.com, but I get no logs:

$ python firefox.py
<empty> 
Flags: needinfo?(yellowhat46)

I would suggest that you try without any additional options first and then please create trace logs as requested. The above logs from Selenium are not helpful.

Ok,
If I run:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()

I get a banner with the error:

Your Firefox profile cannot be loaded. It may be missing or inaccessible.

If I run:

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"
options.add_argument("--profile /home/vasco/.mozilla")

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()

I open a new firefox window, with the tab that I had open in the previous session but I does not go to google. Still no logs;

$ python firefox.py
<empty> 

After closing the firefox windows I get this error:

Traceback (most recent call last):
  File "/home/vasco/z/firefox.py", line 11, in <module>
    with webdriver.Firefox(options=options) as driver:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py", line 69, in __init__
    super().__init__(command_executor=executor, options=options)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 208, in __init__
    self.start_session(capabilities)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 292, in start_session
    response = self.execute(Command.NEW_SESSION, caps)["value"]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 347, in execute
    self.error_handler.check_response(response)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/errorhandler.py", line 229, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: Failed to read marionette port

(In reply to yellowhat46 from comment #6)

I get a banner with the error:

Your Firefox profile cannot be loaded. It may be missing or inaccessible.

This might be related to the temporary profile that geckodriver creates in the temp folder by default if no custom location is specified and which is not accessible by Firefox.

Martin, what are the restrictions with Flatpak? I assume the profile needs to be created somewhere in the home folder instead?

Flags: needinfo?(stransky)

(In reply to yellowhat46 from comment #6)

I open a new firefox window, with the tab that I had open in the previous session but I does not go to google. Still no logs;
`
Can you please check if there is a geckodriver.log file in the current working directory? It should contain the required log entries.

Flags: needinfo?(yellowhat46)

If I run:

python -m venv /tmp/env
source /tmp/env/bin/activate
pip install --no-cache selenium webdriver-manager
python firefox.py
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()

I get the banner with error Your Firefox profile cannot be loaded. It may be missing or inaccessible., after click "OK" I see:

$ python firefox.py
Traceback (most recent call last):
  File "/home/vasco/z/firefox.py", line 11, in <module>
    with webdriver.Firefox(options=options) as driver:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py", line 69, in __init__
    super().__init__(command_executor=executor, options=options)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 208, in __init__
    self.start_session(capabilities)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 292, in start_session
    response = self.execute(Command.NEW_SESSION, caps)["value"]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 347, in execute
    self.error_handler.check_response(response)
  File "/tmp/env/lib64/python3.12/site-packages/selenium/webdriver/remote/errorhandler.py", line 229, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: Process unexpectedly closed with status 1

There are not other files (ie geckodriver.log) under the current working directory.

Flags: needinfo?(yellowhat46)

AFAKI Firefox profile for flatpak (from flathub) is located at /home/user_name/.var/app/org.mozilla.firefox

Flags: needinfo?(stransky)
.var/app/org.mozilla.firefox
├── cache
│   ├── fontconfig
│   ├── mesa_shader_cache
│   ├── mozilla
│   └── tmp
├── config
│   ├── glib-2.0
│   └── pulse
└── data
.mozilla/
├── extensions
└── firefox
    ├── Crash Reports
    ├── custom
    ├── installs.ini
    ├── kb2x7id5.default-release
    ├── lodbpdm7.default
    ├── Pending Pings
    └── profiles.ini

.var/app/org.mozilla.firefox/cache/mozilla/firefox/
├── custom
├── kb2x7id5.default-release
└── lodbpdm7.default

(In reply to Martin Stránský [:stransky] (ni? me) from comment #11)

AFAKI Firefox profile for flatpak (from flathub) is located at /home/user_name/.var/app/org.mozilla.firefox

Thank you. So I assume that a temporary profile that geckodriver creates should be placed somewhere under /home/user_name/.var/ then? Or where is the temporary folder located for Flatpak packages? Sorry, that I have to ask but I don't have a Linux machine.

Component: Widget: Gtk → geckodriver
Product: Core → Testing
Version: Firefox 97 → unspecified
Flags: needinfo?(stransky)

Frankly I have no idea, Jan should know.

Flags: needinfo?(stransky) → needinfo?(jhorak)

I think that I found the answer at https://docs.flatpak.org/en/latest/sandbox-permissions.html under the Filesystem access section:

If an application uses $TMPDIR to contain lock files you may want to add a wrapper script that sets it to $XDG_RUNTIME_DIR/app/$FLATPAK_ID.

yellowhat46, does it work when you run TMPDIR=$XDG_RUNTIME_DIR/app/org.mozilla.firefox/ %command% or even using a subfolder there?

Flags: needinfo?(jhorak) → needinfo?(yellowhat46)
Priority: P3 → --
Summary: Selenium with flatpak does not open the page → When Firefox is installed via Flatpak it fails to access the temporary profile folder

I have just tried to modify:

$ ~/.local/share/flatpak/exports/bin/org.mozilla.firefox
#!/bin/sh

TMPDIR=$XDG_RUNTIME_DIR/app/org.mozilla.firefox/

exec /usr/bin/flatpak run --branch=stable --arch=x86_64 org.mozilla.firefox "$@"
python -m venv /tmp/env
source /tmp/env/bin/activate
curl -L --output /tmp/env/bin/gecko.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.34.0/geckodriver-v0.34.0-linux64.tar.gz
tar xf /tmp/env/bin/gecko.tar.gz  -C /tmp/env/bin
pip install --no-cache selenium webdriver-manager
python firefox.py
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()

I get the banner with error Your Firefox profile cannot be loaded. It may be missing or inaccessible., after click "OK" I see:

Traceback (most recent call last):
  File "/home/vasco/z/a.py", line 8, in <module>
    with webdriver.Firefox(options=options) as driver:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py", line 69, in __init__
    super().__init__(command_executor=executor, options=options)
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 208, in __init__
    self.start_session(capabilities)
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 292, in start_session
    response = self.execute(Command.NEW_SESSION, caps)["value"]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 347, in execute
    self.error_handler.check_response(response)
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/errorhandler.py", line 229, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: Process unexpectedly closed with status 1
Flags: needinfo?(yellowhat46)

This wont work that way. It's geckodriver which needs the overriden TMPDIR environment variable and not Firefox. So the following should probably work:

TMPDIR=$XDG_RUNTIME_DIR/app/org.mozilla.firefox/tmp/ python firefox.py

$ ~/.local/share/flatpak/exports/bin/org.mozilla.firefox
#!/bin/sh
exec /usr/bin/flatpak run --branch=stable --arch=x86_64 org.mozilla.firefox "$@"
from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()
python -m venv /tmp/env
source /tmp/env/bin/activate
curl -L --output /tmp/env/bin/gecko.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.34.0/geckodriver-v0.34.0-linux64.tar.gz
tar xf /tmp/env/bin/gecko.tar.gz  -C /tmp/env/bin
pip install --no-cache selenium webdriver-manager
TMPDIR=$XDG_RUNTIME_DIR/app/org.mozilla.firefox/tmp/ python firefox.py 

Got error:

Traceback (most recent call last):
  File "/home/vasco/z.py", line 8, in <module>
    with webdriver.Firefox(options=options) as driver:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py", line 60, in __init__
    self.service.start()
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/common/service.py", line 102, in start
    self.assert_process_still_running()
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/common/service.py", line 115, in assert_process_still_running
    raise WebDriverException(f"Service {self._path} unexpectedly exited. Status code was: {return_code}")
selenium.common.exceptions.WebDriverException: Message: Service /tmp/env/bin/geckodriver unexpectedly exited. Status code was: 64

Did you create $XDG_RUNTIME_DIR/app/org.mozilla.firefox/tmp/ first? geckodriver is not recursively creating folders. Also checking the geckodriver.log file for the failure might indicate more details.

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()
python -m venv /tmp/env
source /tmp/env/bin/activate
curl -L --output /tmp/env/bin/gecko.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.34.0/geckodriver-v0.34.0-linux64.tar.gz
tar xf /tmp/env/bin/gecko.tar.gz  -C /tmp/env/bin
pip install --no-cache selenium webdriver-manager
mkdir -p $XDG_RUNTIME_DIR/app/org.mozilla.firefox/tmp
TMPDIR=$XDG_RUNTIME_DIR/app/org.mozilla.firefox/tmp/ python firefox.py 

Now it is working as expected.

Thanks

Status: UNCONFIRMED → RESOLVED
Closed: 2 months ago
Resolution: --- → WORKSFORME

Great hear! Nevertheless it would be good if geckodriver could handle that itself and not require the user to do this workaround.

Out of interest does it also work when you set any other folder directly under $XDG_RUNTIME_DIR like $XDG_RUNTIME_DIR/tmp/? Or does that cause Firefox to fail as well in not being able to access the profile folder?

Status: RESOLVED → REOPENED
Ever confirmed: true
Resolution: WORKSFORME → ---

from selenium import webdriver
from selenium.webdriver.firefox.options import Options

options = Options()
options.log.level = "trace"
options.binary_location = "/home/vasco/.local/share/flatpak/exports/bin/org.mozilla.firefox"

with webdriver.Firefox(options=options) as driver:
    driver.get("http://google.com")
    driver.quit()
python -m venv /tmp/env
source /tmp/env/bin/activate
curl -L --output /tmp/env/bin/gecko.tar.gz https://github.com/mozilla/geckodriver/releases/download/v0.34.0/geckodriver-v0.34.0-linux64.tar.gz
tar xf /tmp/env/bin/gecko.tar.gz  -C /tmp/env/bin
pip install --no-cache selenium webdriver-manager
mkdir -p $XDG_RUNTIME_DIR/tmp
TMPDIR=$XDG_RUNTIME_DIR/tmp/ python firefox.py 

I get the banner with error Your Firefox profile cannot be loaded. It may be missing or inaccessible., after click "OK" I see:

Traceback (most recent call last):
  File "/home/vasco/z.py", line 8, in <module>
    with webdriver.Firefox(options=options) as driver:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py", line 69, in __init__
    super().__init__(command_executor=executor, options=options)
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 208, in __init__
    self.start_session(capabilities)
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 292, in start_session
    response = self.execute(Command.NEW_SESSION, caps)["value"]
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/webdriver.py", line 347, in execute
    self.error_handler.check_response(response)
  File "/tmp/env/lib/python3.12/site-packages/selenium/webdriver/remote/errorhandler.py", line 229, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.WebDriverException: Message: Process unexpectedly closed with status 1

Thanks. So it looks like the profile has indeed to be located under org.mozilla.firefox. What I actually missed is that geckodriver also has a --profile-root argument that you could use for the time being by specifying $XDG_RUNTIME_DIR/app/org.mozilla.firefox/tmp/ as the root folder for the to generate Firefox profile by geckodriver.

What we wonder is if Flatpak comes just with Firefox or also with geckodriver bundled (similar to Snap). Do you know that?

Also maybe the discussion and upcoming changes via bug 259356 might be related here as well but probably don't block.

Flags: needinfo?(yellowhat46)
Priority: -- → P3
See Also: → xdg-basedir
Status: REOPENED → NEW

(In reply to Henrik Skupin [:whimboo][⌚️UTC+1] from comment #23)

Thanks. So it looks like the profile has indeed to be located under org.mozilla.firefox. What I actually missed is that geckodriver also has a --profile-root argument that you could use for the time being by specifying $XDG_RUNTIME_DIR/app/org.mozilla.firefox/tmp/ as the root folder for the to generate Firefox profile by geckodriver.

What we wonder is if Flatpak comes just with Firefox or also with geckodriver bundled (similar to Snap). Do you know that?

Also maybe the discussion and upcoming changes via bug 259356 might be related here as well but probably don't block.

If the geckodriver version is not bundled, would there actually be a mismatch between the flatpak "home" (~/.var/app/org.mozilla.firefox/) and the actual home (~) profile locations?

As far as I understood from the code, the flatpak version links its directory with the directory ~/.mozilla (see https://hg.mozilla.org/mozilla-central/file/tip/taskcluster/docker/firefox-flatpak/runme.sh#l160) for reading and writing, so it should be able to both read and write from there, including profiles.

In my opinion, the default message "Your Firefox profile cannot be loaded. It may be missing or inaccessible." is not helpful in this case, since the profile should have been created at runtime (not missing) with the correct permissions (accessible) by geckodriver.
Also, there seems to be some controversy regarding the $TMPDIR usage (see https://github.com/flatpak/flatpak/issues/3438), so wouldn't it be better for geckodriver to just launch firefox providing the full path to the created profile instead of relying on firefox's profile searching algorithm?

We do not rely on the profiles.ini file from Firefox. geckodriver determines on its own the location of the temporary Firefox profile to create. Then question here is how as best determine that location. If geckodriver would be bundled similar to Snap its getting run from within the Snap environment and as such also knows where to put the profile. But running it outside like when seperately downloaded from the gitHub website it doesn't know if the Firefox binary to run is part of a package or not.

Maybe the best here is to indeed also suggest to use the --profile-root argument to specify the profile location. We could update our documentation to explicitly lay out specific directories for Snap, Flatpak, and others.

https://firefox-source-docs.mozilla.org/testing/geckodriver/Usage.html#running-firefox-in-a-container-based-package

See also bug 1819377 which is the equivalent for Snap.

See Also: → 1819377

geckodriver determines on its own the location of the temporary Firefox profile to create. Then question here is how as best determine that location

This is the part I'm confused about. Should the profile location even matter if geckodriver could launch firefox and then provide the full path to the created profile? Even if firefox may see a different filesystem, by providing a full path this restriction would be bypassed.

Specifically, I'm confused if geckodriver couldn't just launch firefox like so ${FIREFOX_BINARY} --profile <path>

That is the argument that geckodriver is using. But the temporary profile is created at /tmp/* so it's not accessible by Firefox as from the Flatpak. This is not about the filesystem but sandboxing. See my comment 15 with a link.

I see now, so passing a folder/path as an argument is not the same as enabling read/write access to it within the flatpak sandbox. This seems to open two possible behaviors ("check for sandbox" versus "use common location"):

  1. "use common location": Is there a directory location with read/write access to both a normal and a sandboxed Firefox install? (maybe $XDG_CACHE_HOME)
  2. "check for sandbox": can geckodriver know if Firefox is sandboxed (i.e.: it doesn't have read/write access to the default /tmp dir) before launching it?

From taking a look at the source code:

geckodriver seems to get the binary as a string from the --binary flag, then fallback_binary and finally mozrunner::platform::firefox::firefox_default_path according to the . I'm not sure when fallback_binary is used, but since this is the information is passed as a string/path, geckodriver would need to check by itself.

It can maybe use running_as_snap from mozrunner::platform, and we could add a running_as_flatpak for completeness. If not, is it doable to check if firefox is a snap/flatpak by checking for these directories (~/.var/app/org.mozilla.firefox and ~/snap/firefox/common)?

In the "check for sandbox" method, I can think of some approaches to then fix the current issue:

  1. geckodriver could set the TMPDIR environmental variable accordingly and even warn in case --profile-root is not accessible to Firefox
  2. geckodriver could mangle the --profile-root option if it is not provided (I think this would be a bad idea lol)
  3. geckodriver could pass along a flag/enum to mozprofile so that it uses a suitable temporary directory instead of /tmp
  4. mozprofile itself could be updated to check if the installed firefox is sandboxed

The third and fourth approaches would require some changes to the write access check in main.rs that would maybe create some duplication between geckodriver and mozprofile.

Considering the two use cases of a named profile (seems deprecated) and a new temporary profile, both seem to be created in FirefoxOptions::load_profile, which currently sends only the profile-root path.

I'm not sure if the third and fourth approaches would work as expected, since geckodriver could still create other temporary files that Firefox doesn't have access to, while the first approach should be able to deal with that by default. The fourth approach also has the drawback of added complexity for mozprofile, which would then need more Linux-specific code.

Dumb question, but I found that there are both python and rust files/implementations, I'd like to ask which one is actually used by firefox so that I can link the correct source code.

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: