Skip to content

Stop Zen asking to be the default, in a file zen-browser-bin updates leave alone - #15909

Open
stevederico wants to merge 2 commits into
omacom:quattrofrom
stevederico:fix/zen-default-prompt
Open

stevederico wants to merge 2 commits into
omacom:quattrofrom
stevederico:fix/zen-default-prompt

Conversation

@stevederico

Copy link
Copy Markdown

Fixes #15870

Since 4.0.5, every link goes through omarchy-browser.desktop. Zen never sees itself as the default browser, so it asks to become the default on every launch. #14441 turns that check off for Firefox-family browsers with the DontCheckDefaultBrowser policy, but for Zen it looked in /opt/zen-browser/distribution. The zen-browser-bin package the menu installs lives in /opt/zen-browser-bin.

Pointing at the right directory is not enough. /opt/zen-browser-bin/distribution/policies.json belongs to the package and is not in its backup array. Every zen-browser-bin upgrade (omarchy update runs yay -Sua) writes the package's copy back, so a setting added there lasts only until the next update.

What changed

  • install/helpers/browser-policy.sh: new browser_policy_setup_zen_policies.
    • It creates /etc/zen/policies/policies.json from the package's policies.json, so DisableAppUpdate and DefaultSerialGuardSetting still apply.
    • It then adds DontCheckDefaultBrowser with browser_policy_firefox_skip_default_check, the helper Route links from every app through the running default browser #14441 added.
    • If an administrator already has an /etc/zen/policies/policies.json, it is kept and only gets the setting added.
    • It does nothing when zen-browser-bin is not installed.
    • Directories are root 0755 and the file is root 0644, using the existing hardened helpers.
    • The file it creates carries a top-level __COMMENT__ marker next to "policies". Zen reads only .policies (JSON.parse(data).policies), so the marker has no effect on Zen.
  • bin/omarchy-install-browser zen calls it.
  • migrations/1792363203.sh calls it for existing Zen installs, which Route links from every app through the running default browser #14441's migration missed.
  • bin/omarchy-remove-browser zen calls the new browser_policy_remove_zen_policies, once omarchy-pkg-missing zen-browser-bin confirms the package is gone.
    • It deletes /etc/zen/policies/policies.json only if it carries Omarchy's marker.
    • It then removes /etc/zen/policies and /etc/zen only if they are empty.
    • This follows the existing removers. Chrome and Edge delete only Omarchy's own files from /etc/opt/<browser>/policies/managed. Brave checks that the package is gone before it touches /etc/brave.
    • An administrator's file is never deleted. It keeps the DontCheckDefaultBrowser it was given, just as an administrator's Firefox policies.json keeps it after Firefox is removed. Nothing removes merged keys today, and the setting does nothing once Zen is gone.

pacman never writes to /etc/zen, so the setting survives package updates.

Why /etc/zen/policies, and not a pacman hook

  • Zen reads this file. I read the files in the zen-browser-bin 1.23.3b release tarball, and Firefox's source.
    • On Linux, JSONPoliciesProvider._getLocalConfigurationFile() returns SysConfD/policies/policies.json when that file exists. Otherwise it returns distribution/policies.json.
    • SysConfD is /etc plus the app name, lowercased (GetUnixSystemConfigDir in xpcom/io/SpecialSystemDirectory.cpp).
    • Zen's AppConstants has MOZ_APP_NAME: "zen" and MOZ_SYSTEM_POLICIES: true, and its application.ini has Name=Zen.
    • Zen's own Flatpak build creates /app/etc/zen, which is the Flatpak form of the same directory.
  • It replaces the package file, it does not merge with it. Linux has one JSON provider, which reads only the first file it finds. That is why the /etc file starts as a copy of the package's policies.
  • Omarchy already does this. Chromium-family policy lives in /etc/<browser>/policies/managed. The open LibreWolf PR (Add LibreWolf as supported browser #13309) uses /etc/librewolf/policies the same way, seeded from the packaged file.
  • A pacman hook needs a second repo. omarchy-pkgs/pkgbuilds/omarchy/PKGBUILD installs each hook by name. Temporary passwordless sudo always fails: 05-omarchy-passwordless-revoke.hook is never installed by packaging #14733 is a hook that sits in this repo but was never packaged, so a hook here alone would ship nothing. No existing hook targets a browser package.

DontCheckDefaultBrowser sets and locks browser.shell.checkDefaultBrowser to false. Zen's startup prompt is Firefox's DefaultBrowserCheck, which skips its check when that pref is false.

Relation to #12148 / #7444

Both fix #7411: Omarchy's Firefox preferences never reach Zen. They write into the package's distribution/policies.json, which has the same update problem. Once /etc/zen/policies/policies.json exists, Zen ignores that file.

  • On a fresh install the order still works: Point Zen's policy at the directory the package uses #12148 writes the distribution file first, then this change copies it into /etc, preferences included.
  • After that, preferences belong in /etc/zen/policies. Whichever PR lands second should seed or merge there.

This PR does not touch the /opt/zen-browser/distribution line or BROWSER_POLICY_FIREFOX_DIRS; that is #12148's fix.

Testing

  • bash test/shell.d/zen-default-browser-check-test.sh: 7/7 ok.
    • It runs the real helper, migration, installer and remover, with Zen's two paths moved into a scratch dir.
    • Its sudo stub only runs commands whose paths are all inside the scratch dir.
    • It checks the file Zen would read (/etc/zen first, then distribution) after the migration and after the installer.
    • It then writes the package's policies.json back, as an upgrade does, and checks again.
    • It also covers:
      • with no zen-browser-bin, nothing is written
      • the migration runs twice without change
      • omarchy-remove-browser zen after an install leaves no /etc/zen
      • an administrator's own /etc/zen/policies/policies.json survives both install and removal
  • Fails without the fix:
    • Adding the setting to the package's policies.json instead: not ok - Zen keeps DontCheckDefaultBrowser after zen-browser-bin rewrites its policies.json
    • Installer call removed: not ok - the installer adds DontCheckDefaultBrowser to Zen's policies and keeps the package's
    • Migration removed: not ok - a migration adds Zen's default browser setting
    • Unmodified quattro: not ok - the helper keeps Zen's setting in /etc/zen/policies, ...
    • Remover unchanged: not ok - removing Zen deletes the /etc/zen Omarchy wrote
    • Remover deleting any policies.json, without the marker check: not ok - removing Zen keeps an administrator's /etc/zen policies
  • platform-app-hooks-test.sh stubs the new helper. It passes, as do default-apps, browser-policy-dir, default-browser-check-migration, browser-link-handoff and config.
  • bash test/shell, run twice on this branch:
    • i18n-test.sh (da/menu.json mirrors the English catalog) fails both times. It also fails on unmodified quattro (60f5b49).
    • In the parallel runs, one or two more files failed each time: input-indicator, update-stay-awake-security, menu-images and pacman-templates, a different set each run. Each one passes alone, and none of them touches browsers or policies.

Not tested:

  • a real zen-browser-bin install
  • about:policies listing DontCheckDefaultBrowser
  • a real launch with no prompt
  • a real zen-browser-bin upgrade
  • a real omarchy remove browser zen

Known limits:

  • The /etc file is a copy of the package's policies taken at install or migration time. If zen-browser-bin later adds a policy key, it will not show up there.
  • If someone edits Omarchy's /etc/zen file in place, the marker stays, and removing Zen deletes it along with their edits.

…leave alone

Since links go through omarchy-browser.desktop, Zen never sees itself as the
default and asks on every launch. omacom#14441 stops that with Firefox's
DontCheckDefaultBrowser policy, but looked for Zen in /opt/zen-browser. The
zen-browser-bin package lives in /opt/zen-browser-bin, and the
distribution/policies.json there belongs to the package: pacman writes it
back on every upgrade, so a setting added to it lasts until the next
omarchy update.

On Linux, Zen reads /etc/zen/policies/policies.json in place of that file
whenever it exists (the system config dir is /etc plus the lowercased app
name, and the JSON provider takes the first file it finds, without merging).
The Zen installer now starts that file from the package's policies, so
DisableAppUpdate and DefaultSerialGuardSetting still apply, and adds
DontCheckDefaultBrowser with the helper omacom#14441 added. A file an
administrator already put there is kept and only gets the setting. A
migration does the same for Zen installs that predate this.

The file Omarchy writes carries a top-level __COMMENT__ marker beside
"policies", which Zen ignores. Removing Zen deletes that file, and only that
file, once the package is gone, then /etc/zen/policies and /etc/zen if they
are empty. An administrator's file stays, as Firefox's policies.json does
when Firefox is removed.
@greptile-apps

greptile-apps Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the previous test-safety issue is fixed.

Summary

The PR keeps Zen’s default-browser setting in /etc/zen/policies/policies.json, outside the package’s update path.

  • Zen's default-browser prompt stays off after package updates.

Reviews (2) · Last reviewed commit: "Keep the Zen test's privileged writes in..." · Reviewed by Greptile

Comment thread test/shell.d/zen-default-browser-check-test.sh
… root

as_root runs commands directly when EUID is 0, so a root run skipped the sudo stub and the real installer's browser_policy_setup_firefox_distribution wrote the host's /opt/zen-browser/distribution/policies.json, while the scratch-tree check still passed. Route as_root through the stub, as brave-widevine-test does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@omarchybot omarchybot added bug Something isn't working verified Omarchy Triage has verified that this issue is ready for final review labels Oct 19, 2026
@omarchybot

Copy link
Copy Markdown
Collaborator

Reviewed and verified on a disposable Omarchy worker with real zen-browser-bin 1.23.2b. The fix works, and I pushed one commit that changes only the new test.

Reproduction. On quattro, with Zen set as the default browser and links routed through omarchy-browser.desktop, Zen's second launch shows "Make Zen your default browser?". After this branch's migration writes /etc/zen/policies/policies.json, the prompt is gone. It stays gone after reinstalling zen-browser-bin, which rewrites /opt/zen-browser-bin/distribution/policies.json. Deleting /etc/zen brings the prompt back. Running the branch's omarchy-install-browser zen writes the file with the package's two policies plus DontCheckDefaultBrowser, and omarchy-remove-browser zen removes the package and /etc/zen.

Pushed: 2cf5703. If test/shell.d/zen-default-browser-check-test.sh runs as root, as_root skips the sudo stub. The real installer's browser_policy_setup_firefox_distribution /opt/zen-browser/distribution then writes the host's /opt/zen-browser/distribution/policies.json, and the "written only inside the scratch tree" check still passes. I confirmed this on the worker. The test's helper wrapper now routes as_root through the stub, as brave-widevine-test.sh does. It passes 7/7 as a normal user and as root, and nothing outside the scratch tree is written. This is the issue Greptile raised.

Tests on the worker. ./test/cli is green. The new test and platform-app-hooks, default-apps, browser-policy-dir, default-browser-check-migration and browser-link-handoff all pass. Eight test/shell.d files fail on this branch: ascii, branding-about-animation, brave-widevine, hyprland-startup-cursor-cold, i18n, lock-appear-budget, passwordless-grant-lifecycle and runtime-smoke. They fail identically on the base commit 60f5b49, so none of them comes from this change. Because the full suite is not green, this is not marked ready.

Second opinion. Codex Medium reviewed the head with my commit and raised three points, none of which I changed:

  • It found no ancestor check when /etc/zen/policies/policies.json already exists. Exploiting that needs /etc/zen to be writable by a non-root user, which only root can arrange.
  • The migration adds the setting to an administrator's leftover /etc/zen file after Zen has been removed. That case is rare, and the result is one sudo prompt and a harmless key.
  • A future __COMMENT__ in the package's file would override the marker. The package has none today, and the effect would be a file left behind on removal.

In a second round, shown that reasoning, it agreed nothing blocking remains. That is agreement with reasoning it had read, so independence is not guaranteed.

For the maintainer. The body's phrase "Both fix #7411" makes GitHub link #7411 as closed by this PR. This PR does not fix #7411: Omarchy's Firefox preferences still go to /opt/zen-browser/distribution, which is #12148's and #7444's job. Merging it would close #7411 anyway, so the wording should change before merge. Also, once /etc/zen/policies/policies.json exists, Zen stops reading distribution/policies.json. #12148 and #7444 would then need to write there instead, as the description notes.

This waits on the maintainer: on the pre-existing suite failures, and on whether to merge.

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

Labels

bug Something isn't working verified Omarchy Triage has verified that this issue is ready for final review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zen-browser-bin still prompts to become the default after link routing Zen installer writes policies to unused /opt/zen-browser path

2 participants