commit 7ae138a2c58f184aed3c3a7d252e82db8633220e
parent 6cbecf227bcb4b3e9088636030a3b431a5ed1a89
Author: Benjamin VanderSloot <bvandersloot@mozilla.com>
Date: Tue, 6 Jan 2026 13:44:12 +0000
Bug 2007918 - Add telemetry to count configuration issues and a pref to be able to disable the security-privacy-status card - r=hjones,emz
Differential Revision: https://phabricator.services.mozilla.com/D277606
Diffstat:
3 files changed, 140 insertions(+), 2 deletions(-)
diff --git a/browser/components/preferences/metrics.yaml b/browser/components/preferences/metrics.yaml
@@ -414,3 +414,47 @@ aboutpreferences:
telemetry_mirror: Aboutpreferences_Show_Hash
no_lint:
- COMMON_PREFIX
+
+security.preferences.warnings:
+ warnings_shown:
+ type: event
+ description: >
+ Recorded when the security warnings card is possibly added to the page
+ in about:preferences#privacy. This tracks the count of visible
+ security warning items to understand how many issues users are seeing.
+ This only fires once per time the settings page is loaded.
+ bugs:
+ - https://bugzilla.mozilla.org/2007918
+ data_reviews:
+ - https://bugzilla.mozilla.org/2007918
+ notification_emails:
+ - bvandersloot@mozilla.com
+ expires: never
+ extra_keys:
+ count:
+ description: The number of visible security warning items in the card
+ type: quantity
+ warning_fixed:
+ type: event
+ description: >
+ Recorded when the user interacts with the "fix" button in the issue box
+ item.
+ bugs:
+ - https://bugzilla.mozilla.org/2007918
+ data_reviews:
+ - https://bugzilla.mozilla.org/2007918
+ notification_emails:
+ - bvandersloot@mozilla.com
+ expires: never
+ warning_dismissed:
+ type: event
+ description: >
+ Recorded when the user interacts with the dismiss button in the issue box
+ item.
+ bugs:
+ - https://bugzilla.mozilla.org/2007918
+ data_reviews:
+ - https://bugzilla.mozilla.org/2007918
+ notification_emails:
+ - bvandersloot@mozilla.com
+ expires: never
diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js
@@ -299,6 +299,7 @@ Preferences.addAll([
if (SECURITY_PRIVACY_STATUS_CARD_ENABLED) {
Preferences.addAll([
// Security and Privacy Warnings
+ { id: "browser.preferences.config_warning.dismissAll", type: "bool" },
{ id: "privacy.ui.status_card.testing.show_issue", type: "bool" },
{
id: "browser.preferences.config_warning.warningTest.dismissed",
@@ -812,6 +813,8 @@ class WarningSettingConfig {
if (isDismissable) {
this.dismissedPrefId = `browser.preferences.config_warning.${this.id}.dismissed`;
this.prefMapping.dismissed = this.dismissedPrefId;
+ this.dismissAllPrefId = `browser.preferences.config_warning.dismissAll`;
+ this.prefMapping.dismissAll = this.dismissAllPrefId;
}
this.problematic = problematic;
}
@@ -823,7 +826,11 @@ class WarningSettingConfig {
* @returns {boolean} Whether or not to show this configuration as a warning to the user
*/
visible() {
- return !this.dismissed?.value && this.problematic(this);
+ return (
+ !this.dismissAll?.value &&
+ !this.dismissed?.value &&
+ this.problematic(this)
+ );
}
/**
@@ -878,10 +885,12 @@ class WarningSettingConfig {
switch (event.target.id) {
case "reset": {
this.reset();
+ Glean.securityPreferencesWarnings.warningFixed.record();
break;
}
case "dismiss": {
this.dismiss();
+ Glean.securityPreferencesWarnings.warningDismissed.record();
break;
}
}
@@ -1416,7 +1425,14 @@ if (SECURITY_PRIVACY_STATUS_CARD_ENABLED) {
id: "warningCard",
deps: SECURITY_WARNINGS.map(warning => warning.id),
visible: deps => {
- return Object.values(deps).some(depSetting => depSetting.visible);
+ const count = Object.values(deps).filter(
+ depSetting => depSetting.visible
+ ).length;
+ if (!this._telemetrySent) {
+ Glean.securityPreferencesWarnings.warningsShown.record({ count });
+ this._telemetrySent = true;
+ }
+ return count > 0;
},
});
}
diff --git a/browser/components/preferences/tests/browser_privacy_status_card.js b/browser/components/preferences/tests/browser_privacy_status_card.js
@@ -208,6 +208,7 @@ add_task(async function test_issue_fix() {
["privacy.ui.status_card.testing.show_issue", true],
].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
});
+ Services.fog.testResetFOG();
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
@@ -239,6 +240,28 @@ add_task(async function test_issue_fix() {
),
"Pref has no user value after clicking the fix button"
);
+ let events =
+ Glean.securityPreferencesWarnings.warningFixed.testGetValue();
+ Assert.equal(events.length, 1, "One telemetry event was recorded");
+ Assert.equal(
+ events[0].category,
+ "security.preferences.warnings",
+ "Category is correct"
+ );
+ Assert.equal(events[0].name, "warning_fixed", "Event name is correct");
+
+ let warningsShownEvents =
+ Glean.securityPreferencesWarnings.warningsShown.testGetValue();
+ Assert.equal(
+ warningsShownEvents.length,
+ 1,
+ "warningsShown telemetry was recorded exactly once"
+ );
+ Assert.equal(
+ warningsShownEvents[0].extra.count,
+ "1",
+ "Count of warnings shown is correct"
+ );
}
);
@@ -252,6 +275,7 @@ add_task(async function test_issue_dismiss() {
["privacy.ui.status_card.testing.show_issue", true],
].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
});
+ Services.fog.testResetFOG();
await BrowserTestUtils.withNewTab(
{ gBrowser, url: "about:preferences#privacy" },
@@ -283,6 +307,31 @@ add_task(async function test_issue_dismiss() {
),
"Pref has no user value after clicking the fix button"
);
+ let events =
+ Glean.securityPreferencesWarnings.warningDismissed.testGetValue();
+ Assert.equal(events.length, 1, "One telemetry event was recorded");
+ Assert.equal(
+ events[0].category,
+ "security.preferences.warnings",
+ "Category is correct"
+ );
+ Assert.equal(
+ events[0].name,
+ "warning_dismissed",
+ "Event name is correct"
+ );
+ let warningsShownEvents =
+ Glean.securityPreferencesWarnings.warningsShown.testGetValue();
+ Assert.equal(
+ warningsShownEvents.length,
+ 1,
+ "warningsShown telemetry was recorded exactly once"
+ );
+ Assert.equal(
+ warningsShownEvents[0].extra.count,
+ "1",
+ "Count of warnings shown is correct"
+ );
Services.prefs.clearUserPref(
"browser.preferences.config_warning.warningTest.dismissed"
);
@@ -292,6 +341,35 @@ add_task(async function test_issue_dismiss() {
await SpecialPowers.popPrefEnv();
});
+add_task(async function test_dismiss_all_hides_issues() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [FEATURE_PREF, true],
+ ["privacy.ui.status_card.testing.show_issue", true],
+ ["browser.preferences.config_warning.dismissAll", true],
+ ].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),
+ });
+
+ await BrowserTestUtils.withNewTab(
+ { gBrowser, url: "about:preferences#privacy" },
+ async function (browser) {
+ let card = getCardAndCheckHeader(
+ browser.contentDocument,
+ "security-privacy-status-ok-header"
+ );
+ assertHappyBullets(card);
+
+ let configCard = browser.contentDocument.getElementById(ISSUE_CONTROL_ID);
+ Assert.ok(
+ BrowserTestUtils.isHidden(configCard),
+ "Issue card is not present when dismissAll is true"
+ );
+ }
+ );
+
+ await SpecialPowers.popPrefEnv();
+});
+
add_task(async function test_update_status_indicator() {
await SpecialPowers.pushPrefEnv({
set: [[FEATURE_PREF, true]].concat(RESET_PROBLEMATIC_TEST_DEFAULTS),