Skip to content

Add notification-driven kill switch for auto-upgrade#7422

Merged
alfonso-noriega merged 1 commit into
mainfrom
add-autoupgrade-notification-switch
Apr 29, 2026
Merged

Add notification-driven kill switch for auto-upgrade#7422
alfonso-noriega merged 1 commit into
mainfrom
add-autoupgrade-notification-switch

Conversation

@alfonso-noriega

@alfonso-noriega alfonso-noriega commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

We need a remote kill switch for CLI auto-upgrade so we can stop a bad release from being silently rolled out further while a fix is in flight. Today, once a user has opted into auto-upgrade, every postrun will attempt to upgrade to the latest cached version with no way for us to halt that flow short of unpublishing.

This PR reuses the existing notifications system as the transport for that kill switch: an error-type notification on a new autoupgrade surface silently disables the auto-upgrade for matching CLI versions / date windows.

WHAT is this pull request doing?

  • Adds hasBlockingAutoUpgradeNotification() in packages/cli-kit/src/public/node/upgrade.ts. It freshly fetches the notifications feed (no cache) and returns true iff there is at least one notification with surface === 'autoupgrade', type === 'error', and matching min/maxVersion + min/maxDate. Lives in the upgrade module rather than the notifications module because the policy (which surface, which type counts as blocking) is auto-upgrade specific.
  • Wires the helper into autoUpgradeIfNeeded's performAutoUpgrade path. The check runs after every existing gate — cached newer version, opt-in, not CI, not pre-release, daily rate limit / SHOPIFY_CLI_FORCE_AUTO_UPGRADE — so:
    • the feed is fetched at most once per day per user, on the day an upgrade would actually happen,
    • users that have auto-upgrade off, are on CI, on a pre-release, or already ran today incur zero overhead.
  • When a blocking notification is found, the upgrade is silently skipped (no outputWarn / outputInfo) and env_auto_upgrade_skipped_reason: 'blocked_by_notification' is recorded for analytics.
  • Fail-open: any error fetching or parsing the feed returns false, with no logging, so a broken notifications endpoint never prevents upgrades.
  • Tests cover the new helper (matching surface/type/version/date, fail-open path) and the postrun branch (silent skip + metadata, and that we don't query notifications when there's nothing to upgrade to).

How to test your changes?

Locally simulate a kill-switch notification and verify that auto-upgrade is silently skipped:

  1. Host a notifications JSON containing an entry like:
    {
      "id": "block-autoupgrade",
      "message": "Auto-upgrade temporarily disabled",
      "type": "error",
      "frequency": "always",
      "ownerChannel": "#cli",
      "surface": "autoupgrade"
    }
  2. Point the CLI at it: export SHOPIFY_CLI_NOTIFICATIONS_URL=....
  3. Force auto-upgrade to attempt: export SHOPIFY_CLI_FORCE_AUTO_UPGRADE=1, with auto-upgrade enabled, on a version older than the latest published @shopify/cli.
  4. Run any non-upgrade / non-notifications Shopify CLI command.

Expected: no upgrade is performed, no warning/info output is shown, and analytics show env_auto_upgrade_skipped_reason=blocked_by_notification. Removing the notification (or changing type to warning) should let the upgrade proceed as before.

Unit tests:

pnpm -F @shopify/cli-kit test src/public/node/upgrade.test.ts src/public/node/hooks/postrun.test.ts

Post-release steps

None.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows) — pure logic on top of existing notifications fetch.
  • I've considered possible documentation changes — no public-facing docs change; the kill-switch contract is operational.
  • I've considered analytics changes to measure impact — added env_auto_upgrade_skipped_reason: 'blocked_by_notification'.
  • This change is internal-only (operational kill switch); no user-facing behavior change and no changeset required.

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@github-actions github-actions Bot added the Area: @shopify/cli @shopify/cli package issues label Apr 29, 2026
@alfonso-noriega alfonso-noriega force-pushed the add-autoupgrade-notification-switch branch 2 times, most recently from 986730c to 45bcc7a Compare April 29, 2026 10:29
@github-actions github-actions Bot added no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. and removed Area: @shopify/cli @shopify/cli package issues labels Apr 29, 2026
@alfonso-noriega alfonso-noriega force-pushed the add-autoupgrade-notification-switch branch from 45bcc7a to e53a12a Compare April 29, 2026 10:31
@alfonso-noriega alfonso-noriega marked this pull request as ready for review April 29, 2026 10:33
@alfonso-noriega alfonso-noriega requested a review from a team as a code owner April 29, 2026 10:33
@alfonso-noriega alfonso-noriega force-pushed the add-autoupgrade-notification-switch branch from e53a12a to e14c9f7 Compare April 29, 2026 10:52
@alfonso-noriega alfonso-noriega force-pushed the add-autoupgrade-notification-switch branch from e14c9f7 to c8123b6 Compare April 29, 2026 10:58
@github-actions

Copy link
Copy Markdown
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/public/node/upgrade.d.ts
@@ -22,6 +22,18 @@ export declare function runCLIUpgrade(): Promise<void>;
  * @returns The version string to upgrade to, or undefined if no upgrade should happen.
  */
 export declare function versionToAutoUpgrade(): string | undefined;
+/**
+ * Checks the freshly fetched notifications feed for a kill-switch notification that
+ * disables auto-upgrade. A blocking notification is one with ,
+ * , and matching version/date ranges for the current CLI.
+ *
+ * Fails open: any error fetching or parsing the feed results in , so a broken
+ * notifications endpoint never prevents users from auto-upgrading. Intentionally silent
+ * (no logs) — this is invoked on the auto-upgrade hot path.
+ *
+ * @returns  when an active blocking notification is found,  otherwise.
+ */
+export declare function hasBlockingAutoUpgradeNotification(): Promise<boolean>;
 /**
  * Shows a daily upgrade-available warning for users who have not enabled auto-upgrade.
  * Skipped in CI and for pre-release versions. When auto-upgrade is enabled this is a no-op

@isaacroldan isaacroldan left a comment

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.

Nice!

@alfonso-noriega alfonso-noriega added this pull request to the merge queue Apr 29, 2026
Merged via the queue into main with commit e4b461c Apr 29, 2026
47 of 49 checks passed
@alfonso-noriega alfonso-noriega deleted the add-autoupgrade-notification-switch branch April 29, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants