Skip to content

Linux: auto-trust Firefox profiles and surface in-app cert notice#3472

Open
gavande1 wants to merge 8 commits into
trunkfrom
rsm-2943-linux-show-in-app-cert-trust-notice-with-browser-specific
Open

Linux: auto-trust Firefox profiles and surface in-app cert notice#3472
gavande1 wants to merge 8 commits into
trunkfrom
rsm-2943-linux-show-in-app-cert-trust-notice-with-browser-specific

Conversation

@gavande1
Copy link
Copy Markdown
Contributor

@gavande1 gavande1 commented May 13, 2026

Related issues

  • Fixes RSM-2943 — Linux: auto-trust the Studio CA in Firefox profiles
  • Fixes RSM-2944 — Linux: auto-install root CA into Firefox profiles

How AI was used in this PR

Implementation drafted with Claude Code. Tests, types, and the flow described in the testing instructions below were verified manually inside the Linux VM. @ivan-ottinger also drafted #3488 to demonstrate a simpler alternative that drops the in-app Firefox-specific notice and relies on refetchOnFocus for the trust-after-first-launch case; that commit has been folded into this PR.

Proposed Changes

  • Extend trustRootCA() on Linux to also import the Studio CA into every existing Firefox profile NSS DB (cert9.db) across apt (~/.mozilla/firefox/*.default*), Snap (~/snap/firefox/common/.mozilla/firefox/*.default*), and Flatpak (~/.var/app/org.mozilla.firefox/.mozilla/firefox/*.default*) install roots.
  • Extend isRootCATrusted() on Linux to also verify each existing Firefox profile contains the cert, so the existing Trust Certificate notice reappears if a profile drifts. Profiles that don't exist yet are vacuously trusted (Firefox creates cert9.db on first launch — nothing to check or import into until then).
  • New tools/common/lib/linux-trust-store.ts helpers: getLinuxFirefoxProfileDbDirs, areAllFirefoxProfilesTrustedLinux, importCAIntoFirefoxProfilesLinux. They mirror the existing getLinuxNssDbCandidates / isCAImportedInUserNssDbsLinux / importCAIntoUserNssDbsLinux pattern.
  • The "Firefox installed but never launched" gap is handled by the existing refetchOnFocus: true on certificateTrustApi + setupListeners(store.dispatch) in stores/index.ts. When the user launches Firefox for the first time and returns focus to Studio, the trust check re-runs, finds an untrusted new profile DB, and the existing notice + Trust Certificate button reappear. One more click silently imports into the new profile (no sudo prompt — the system bundle install short-circuits when the cert is already in /etc/ssl/certs).

Testing Instructions

Run inside the Linux VM (ssh parallels@10.211.55.3, project at /home/parallels/Desktop/studio-linux).

Auto-import into existing Firefox profile

  1. Launch Firefox at least once so a .default* profile with cert9.db exists.
  2. Make sure the Studio CA is currently untrusted (see Reset below).
  3. Start Studio, open a site, enable HTTPS. The HTTPS row shows Disabled / Enabled with a Trust Certificate button and the untrusted-cert notice.
  4. Click Trust Certificate, complete the polkit prompt. Button and notice disappear.
  5. Verify the cert landed in Firefox: certutil -d sql:$HOME/.mozilla/firefox/<id>.default-release -L -n 'WordPress Studio CA' should succeed. Repeat for the snap / flatpak profile roots if you have those installations.
  6. Open the site in Firefox — no security warning.

Firefox installed but never launched (trust-then-launch flow)

  1. Reset trust (see Reset below) and remove any Firefox profile dirs: rm -rf ~/.mozilla/firefox ~/snap/firefox/common/.mozilla/firefox ~/.var/app/org.mozilla.firefox/.mozilla/firefox.
  2. Start Studio, open a site, enable HTTPS. Click Trust Certificate.
  3. System bundle + Chromium NSS import happen; Firefox import is a no-op (no profile yet). Button and notice hide.
  4. Launch Firefox for the first time, then return focus to Studio.
  5. The untrusted-cert notice + Trust Certificate button reappear (refetch-on-focus picks up the freshly-created profile DB).
  6. Click Trust Certificate again — should run without a polkit prompt (system bundle is already trusted; only the NSS imports execute).
  7. Reload the site in Firefox — no security warning.

Trust-state regression

  1. With cert trusted, remove just the Firefox profile copy:
    certutil -d sql:$HOME/.mozilla/firefox/<id>.default-release -D -n 'WordPress Studio CA'
  2. Return focus to Studio → notice + Trust button should reappear on refetch.
CleanShot.2026-05-13.at.21.20.36.mp4

Note: the recording above was made before #3488's changes were folded in; it shows the older flow that included a second Firefox-specific notice. The current behavior matches the steps above (one notice, not two).

No regressions on macOS / Windows

  • On both, the Trust Certificate flow behaves exactly as before; nothing Linux-specific is triggered.

Reset trusted certificate (for re-testing)

sudo rm -f /usr/local/share/ca-certificates/studio-ca.crt && sudo update-ca-certificates --fresh
certutil -d sql:$HOME/.pki/nssdb -D -n 'WordPress Studio CA' || true
certutil -d sql:$HOME/snap/chromium/current/.pki/nssdb -D -n 'WordPress Studio CA' 2>/dev/null || true
for p in $HOME/.mozilla/firefox/*.default* $HOME/snap/firefox/common/.mozilla/firefox/*.default* $HOME/.var/app/org.mozilla.firefox/.mozilla/firefox/*.default*; do
  [ -d "$p" ] && certutil -d sql:"$p" -D -n 'WordPress Studio CA' 2>/dev/null || true
done

Tests

npm test -- tools/common/lib/tests/linux-trust-store.test.ts apps/studio/src/components/tests/content-tab-settings.test.tsx

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

…in-app-cert-trust-notice-with-browser-specific
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends Studio’s Linux certificate trust flow to better support Firefox by importing the Studio root CA into existing Firefox profile NSS databases and showing an in-app notice linking to manual steps when Firefox is detected.

Changes:

  • Add Linux helpers to discover Firefox profile NSS DBs (cert9.db), import the CA into them, and verify trust across all existing profiles.
  • Update Linux trust checks/imports to include Firefox profiles in addition to the system bundle and Chromium-family NSS DBs.
  • Add a Linux-only UI notice + IPC/RTK Query wiring to detect Firefox presence and link users to Firefox-specific SSL docs.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tools/common/lib/linux-trust-store.ts Adds Firefox-profile discovery, trust verification, and CA import helpers for Linux.
tools/common/lib/tests/linux-trust-store.test.ts Adds unit tests for Firefox profile DB discovery helper.
apps/studio/src/lib/certificate-manager.ts Extends Linux trust verification and trust flow to include Firefox profile imports/checks.
apps/studio/src/lib/detect-linux-browsers.ts Adds Linux Firefox detection (PATH + common data dirs).
apps/studio/src/lib/tests/detect-linux-browsers.test.ts Adds tests for Firefox detection logic (currently has a mocking issue).
apps/studio/src/ipc-handlers.ts Adds IPC handler to surface Firefox-detected status to the renderer on Linux.
apps/studio/src/preload.ts Exposes new IPC method in the preload bridge.
apps/studio/src/stores/certificate-trust-api.ts Adds RTK Query endpoint to fetch Firefox-detected status, tagged with CertificateTrust.
apps/studio/src/components/content-tab-settings.tsx Shows a Linux-only Firefox certificate notice when cert isn’t trusted and Firefox is detected.
apps/studio/src/lib/get-localized-link.ts Adds docs link key for the Linux Firefox SSL anchor.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/studio/src/lib/tests/detect-linux-browsers.test.ts Outdated
@gavande1 gavande1 requested review from a team and ivan-ottinger May 13, 2026 16:52
@gavande1 gavande1 marked this pull request as ready for review May 13, 2026 16:54
@wpmobilebot
Copy link
Copy Markdown
Collaborator

wpmobilebot commented May 14, 2026

📊 Performance Test Results

Comparing 98cfd90 vs trunk

app-size

Metric trunk 98cfd90 Diff Change
App Size (Mac) 1409.64 MB 1409.65 MB +0.01 MB ⚪ 0.0%

site-editor

Metric trunk 98cfd90 Diff Change
load 1498 ms 1506 ms +8 ms ⚪ 0.0%

site-startup

Metric trunk 98cfd90 Diff Change
siteCreation 8586 ms 8583 ms 3 ms ⚪ 0.0%
siteStartup 4935 ms 4944 ms +9 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

Copy link
Copy Markdown
Contributor

@ivan-ottinger ivan-ottinger left a comment

Choose a reason for hiding this comment

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

Thank you for your work on this PR, Rahul!

I am yet to review and test the PR fully and would like to share initial thoughts I have had so far.

Comment on lines +159 to +170
{ ! isCertificateTrusted &&
selectedSite.enableHttps &&
linuxBrowserCertStatus?.firefoxDetected && (
<div className="mt-1 max-w-96" data-testid="trust-cert-firefox-notice">
<span className="text-frame-text-secondary mt-1">
{ __(
'Firefox uses its own certificate store. If Firefox doesn’t recognize the certificate, import it manually to avoid the security warning.'
) }
</span>{ ' ' }
<LearnHowLink docsLinksKey="docsSslLinuxFirefox" />
</div>
) }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What if we kept only the original notice we already have on trunk? Instead of adding this new one we could:

  • rely on the new docs section, e.g. "If you use Firefox on Linux" to communicate potential issue to the user
  • ensure the existing notice is displayed even in that very edge case where the user has Firefox installed, but haven't launched it yet.

I think that could streamline the user experience and also make the code simpler.

Copy link
Copy Markdown
Contributor Author

@gavande1 gavande1 May 14, 2026

Choose a reason for hiding this comment

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

Thanks Ivan, I want to push back a bit here. My biggest concern with falling back to just the existing notice is what it would take to also cover the "Firefox installed but never launched" case you mentioned. Are you comfortable with the notice being persistently visible in the settings tab? That's the part I'm most hesitant about.

The existing notice is gated on !isCertificateTrusted. On Linux that already factors in Firefox profile trust via areAllFirefoxProfilesTrustedLinux, but it's vacuously true when no profile exists — so to surface the notice in the installed-but-never-launched case, we'd have to gate it on something like isFirefoxInstalled, or make isRootCATrusted return false in that scenario. Either way, that signal doesn't auto-clear: a user who has Firefox installed (common on Ubuntu, where it ships by default) but never launches it would see the notice sitting in settings indefinitely.

To be upfront about the tradeoff: my current PR doesn't really solve that edge case either — the new Firefox notice is also gated on !isCertificateTrusted, so it stays silent until a profile actually exists. The difference is that when a profile does show up, the user gets Firefox-specific guidance instead of the generic message, and isFirefoxInstalledOnLinux is what lets us know to do that. I'd rather lean on docs for the never-launched case than make the notice permanent for everyone with Firefox preinstalled.

What I was going for overall is the closest analog to the Chrome trust-status check we already have: only surface platform-specific guidance when it's actionable. Happy to trim the supporting code if parts feel heavy — but I'd like to keep the conditional surfacing rather than collapsing it into a docs-only path. WDYT?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey Rahul! 👋🏼 I created this draft PR to illustrate what I meant: #3488. Basically, there would be just one notice that would be there only when it makes sense. So if the user did not start Firefox, the notice would not be rendered.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks Ivan — your draft made this much easier to evaluate, and it landed exactly where you said it would: tested the trust-then-launch flow end-to-end on the Linux VM and the existing notice reappears on focus return as you described, then the second Trust click silently imports into the new profile.

Folded your commit into this PR as 1194d83f, so the new Firefox notice + its detection/IPC/RTK Query plumbing are all gone. Updating the PR description next to reflect the new shape. Happy to leave #3488 to you to close once you've had a chance to look.

en: 'https://developer.wordpress.com/docs/developer-tools/studio/ssl-in-studio/',
},
docsSslLinuxFirefox: {
en: 'https://developer.wordpress.com/docs/developer-tools/studio/ssl-in-studio/#linux-firefox',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In relation to https://github.com/Automattic/studio/pull/3472/changes#r3240894626 we could do https://developer.wordpress.com/docs/developer-tools/studio/ssl-in-studio/#linux.

That would lead to a new Linux heading under the Certificate Trust by platform section.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Resolved by 1194d83fdocsSslLinuxFirefox was removed entirely. The existing notice keeps using docsSslInStudio, so the Linux subsection that lands on that page will be reachable from there.

import path from 'node:path';
import { findOnPath } from 'src/lib/find-on-path';

export function isFirefoxInstalledOnLinux( homeDir: string = os.homedir() ): boolean {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I might be missing something, but from what I see, if we decide to drop that new UI notice, we could get rid of isFirefoxInstalledOnLinux and a few other code parts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 1194d83fisFirefoxInstalledOnLinux, detect-linux-browsers.ts and its test, the IPC handler, the preload binding, and the RTK Query endpoint are all removed.

ivan-ottinger and others added 2 commits May 14, 2026 23:30
Alternative to the new Firefox notice: rely on the existing untrusted-cert
notice + refetchOnFocus (already enabled on certificateTrustApi) to surface
the case where Firefox is opened after the initial Trust click and a new
profile DB appears without the Studio CA.

- Remove the Firefox notice in content-tab-settings
- Remove isFirefoxInstalledOnLinux + detect-linux-browsers tests
- Remove getLinuxBrowserCertSupportStatus IPC handler + preload binding
- Remove the second RTK Query endpoint + hook
- Remove docsSslLinuxFirefox (rely on docsSslInStudio)
- Keep the substantive fix: importCAIntoFirefoxProfilesLinux,
  areAllFirefoxProfilesTrustedLinux, getLinuxFirefoxProfileDbDirs, and
  the composition in isRootCATrusted / trustRootCA

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

4 participants