commit aa9c92eedbe334df8d86938519849ff4063538bd
parent 7bbf79f1dd69a559d47fe0a64e423b2e4d61e4bd
Author: Beth Rennie <beth@brennie.ca>
Date: Fri, 9 Jan 2026 21:10:30 +0000
Bug 2003365 - Add EnterprisePolicy to disable rollouts r=mkaply,nimbus-reviewers,fluent-reviewers,relud,flod
Differential Revision: https://phabricator.services.mozilla.com/D277369
Diffstat:
5 files changed, 50 insertions(+), 10 deletions(-)
diff --git a/browser/components/enterprisepolicies/Policies.sys.mjs b/browser/components/enterprisepolicies/Policies.sys.mjs
@@ -996,6 +996,14 @@ export var Policies = {
},
},
+ DisableRemoteImprovements: {
+ onBeforeAddons(manager, param) {
+ if (param) {
+ manager.disallowFeature("NimbusRollouts");
+ }
+ },
+ },
+
DisableForgetButton: {
onProfileAfterChange(manager, param) {
if (param) {
diff --git a/browser/components/enterprisepolicies/schemas/policies-schema.json b/browser/components/enterprisepolicies/schemas/policies-schema.json
@@ -559,6 +559,10 @@
"type": "boolean"
},
+ "DisableRemoteImprovements": {
+ "type": "boolean"
+ },
+
"DisableSafeMode": {
"type": "boolean"
},
diff --git a/browser/locales/en-US/browser/policies/policies-descriptions.ftl b/browser/locales/en-US/browser/policies/policies-descriptions.ftl
@@ -94,6 +94,8 @@ policy-DisableProfileImport = Disable the menu command to Import data from anoth
policy-DisableProfileRefresh = Disable the Refresh { -brand-short-name } button in the about:support page.
+policy-DisableRemoteImprovements = Prevent { -brand-short-name } from applying performance, stability, and feature changes between updates.
+
policy-DisableSafeMode = Disable the feature to restart in Safe Mode. Note: the Shift key to enter Safe Mode can only be disabled on Windows using Group Policy.
policy-DisableSecurityBypass = Prevent the user from bypassing certain security warnings.
diff --git a/toolkit/components/nimbus/ExperimentAPI.sys.mjs b/toolkit/components/nimbus/ExperimentAPI.sys.mjs
@@ -424,7 +424,10 @@ export const ExperimentAPI = new (class {
}
get rolloutsEnabled() {
- return this.#prefValues.rolloutsEnabled;
+ return (
+ this.#prefValues.rolloutsEnabled &&
+ Services.policies.isAllowed("NimbusRollouts")
+ );
}
get studiesEnabled() {
diff --git a/toolkit/components/nimbus/test/unit/test_policy.js b/toolkit/components/nimbus/test/unit/test_policy.js
@@ -39,6 +39,7 @@ add_setup(function setup() {
async function doTest({
policies,
labsEnabled,
+ rolloutsEnabled,
studiesEnabled,
existingEnrollments = [],
expectedEnrollments,
@@ -75,31 +76,36 @@ async function doTest({
await initExperimentAPI();
Assert.equal(
- ExperimentAPI.studiesEnabled,
- studiesEnabled,
- "Studies are enabled"
- );
- Assert.equal(
ExperimentAPI.labsEnabled,
labsEnabled,
"FirefoxLabs is enabled"
);
+ Assert.equal(
+ ExperimentAPI.rolloutsEnabled,
+ rolloutsEnabled,
+ "Rollouts are enabled"
+ );
+ Assert.equal(
+ ExperimentAPI.studiesEnabled,
+ studiesEnabled,
+ "Studies are enabled"
+ );
Assert.equal(
loader._enabled,
- studiesEnabled || labsEnabled,
+ labsEnabled || rolloutsEnabled || studiesEnabled,
"RemoteSettingsExperimentLoader initialized"
);
Assert.equal(
loader.setTimer.called,
- studiesEnabled || labsEnabled,
+ labsEnabled || rolloutsEnabled || studiesEnabled,
"RemoteSettingsExperimentLoader polling for recipes"
);
Assert.equal(
loader.updateRecipes.called,
- studiesEnabled || labsEnabled,
+ labsEnabled || rolloutsEnabled || studiesEnabled,
"RemoteSettingsExperimentLoader polling for recipes"
);
@@ -127,8 +133,9 @@ add_task(async function testDisableStudiesPolicy() {
await doTest({
policies: { DisableFirefoxStudies: true },
labsEnabled: true,
+ rolloutsEnabled: true,
studiesEnabled: false,
- expectedEnrollments: [],
+ expectedEnrollments: ["rollout"],
expectedOptIns: ["optin"],
});
});
@@ -137,6 +144,7 @@ add_task(async function testDisableLabsPolicy() {
await doTest({
policies: { UserMessaging: { FirefoxLabs: false } },
labsEnabled: false,
+ rolloutsEnabled: true,
studiesEnabled: true,
expectedEnrollments: ["experiment", "rollout"],
expectedOptIns: [],
@@ -146,10 +154,12 @@ add_task(async function testDisableLabsPolicy() {
add_task(async function testNimbusDisabled() {
await doTest({
policies: {
+ DisableRemoteImprovements: true,
DisableFirefoxStudies: true,
UserMessaging: { FirefoxLabs: false },
},
labsEnabled: false,
+ rolloutsEnabled: false,
studiesEnabled: false,
expectedEnrollments: [],
expectedOptIns: [],
@@ -160,9 +170,22 @@ add_task(async function testDisableLabsPolicyCausesUnenrollments() {
await doTest({
policies: { UserMessaging: { FirefoxLabs: false } },
labsEnabled: false,
+ rolloutsEnabled: true,
studiesEnabled: true,
expectedEnrollments: ["experiment", "rollout"],
existingEnrollments: ["optin"],
expectedOptIns: [],
});
});
+
+add_task(async function testDisableRolloutPolicyCausesUnenrollments() {
+ await doTest({
+ policies: { DisableRemoteImprovements: true },
+ labsEnabled: true,
+ rolloutsEnabled: false,
+ studiesEnabled: true,
+ expectedEnrollments: ["experiment"],
+ existingEnrollments: ["rollout"],
+ expectedOptIns: ["optin"],
+ });
+});