From 912644ab2c1ffbade2460603b5215dc21c5e300e Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 26 Aug 2026 19:29:15 +0000
Subject: [PATCH 1/2] =?UTF-8?q?cherry-pick=20of=20#28660=20failed=20?=
=?UTF-8?q?=E2=80=94=20resolve=20conflicts=20manually?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Cherry-pick of fc35aaefff939a2ecf17898c45bf61225453d5ed onto release/2.37 had conflicts.
To resolve:
git fetch origin backport/28660-to-2.37
git checkout backport/28660-to-2.37
git cherry-pick -x -m1 fc35aaefff939a2ecf17898c45bf61225453d5ed
# resolve conflicts
git push origin backport/28660-to-2.37
From 2b7a88df8e978744733718d83c01bb055da2cb5f Mon Sep 17 00:00:00 2001
From: david-fraley <67079030+david-fraley@users.noreply.github.com>
Date: Wed, 26 Aug 2026 14:27:56 -0500
Subject: [PATCH 2/2] fix(site/src/pages/DeploymentSettingsPage): gate
browser-only paywall on entitlement (#28660)
(cherry picked from commit fc35aaefff939a2ecf17898c45bf61225453d5ed)
---
.../SecuritySettingsPage.tsx | 3 +
.../SecuritySettingsPageView.stories.tsx | 60 ++++++++++++++++++-
.../SecuritySettingsPageView.tsx | 6 +-
3 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx
index 5c1a9bf5752..ebcf2b3248f 100644
--- a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx
+++ b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPage.tsx
@@ -14,6 +14,9 @@ const SecuritySettingsPage: FC = () => {
>
diff --git a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.stories.tsx
index a27250bf267..1af6d1d1436 100644
--- a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.stories.tsx
+++ b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.stories.tsx
@@ -1,5 +1,7 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
+import { expect, within } from "storybook/test";
import type { SerpentGroup, SerpentOption } from "#/api/typesGenerated";
+import { docs } from "#/utils/docs";
import { SecuritySettingsPageView } from "./SecuritySettingsPageView";
const group: SerpentGroup = {
@@ -47,6 +49,7 @@ const meta: Meta = {
hidden: false,
},
],
+ isBrowserOnlyEntitled: true,
featureBrowserOnlyEnabled: true,
},
};
@@ -54,7 +57,62 @@ const meta: Meta = {
export default meta;
type Story = StoryObj;
-export const Page: Story = {};
+export const Page: Story = {
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ const docsLinks = canvas.getAllByRole("link", { name: /View docs/ });
+ await expect(docsLinks).toHaveLength(2);
+ await expect(docsLinks[0]).toHaveAttribute("href", docs("/admin/security"));
+ await expect(docsLinks[1]).toHaveAttribute(
+ "href",
+ docs("/admin/networking#browser-only-connections"),
+ );
+ await expect(
+ canvas.getByRole("heading", {
+ name: /Browser-Only Connections Enabled/,
+ }),
+ ).toBeInTheDocument();
+ await expect(
+ canvas.queryByRole("link", { name: /Start trial for free/ }),
+ ).not.toBeInTheDocument();
+ },
+};
+
+export const EntitledAndTurnedOff: Story = {
+ args: {
+ isBrowserOnlyEntitled: true,
+ featureBrowserOnlyEnabled: false,
+ },
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ await expect(
+ canvas.getByRole("heading", {
+ name: /Browser-Only Connections Disabled/,
+ }),
+ ).toBeInTheDocument();
+ await expect(
+ canvas.queryByRole("link", { name: /Start trial for free/ }),
+ ).not.toBeInTheDocument();
+ },
+};
+
+export const NotEntitled: Story = {
+ args: {
+ isBrowserOnlyEntitled: false,
+ featureBrowserOnlyEnabled: false,
+ },
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ await expect(
+ canvas.getByRole("heading", {
+ name: /Browser-Only Connections Disabled/,
+ }),
+ ).toBeInTheDocument();
+ await expect(
+ canvas.getByRole("link", { name: /Start trial for free/ }),
+ ).toBeInTheDocument();
+ },
+};
export const NoTLS = {
args: {
diff --git a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.tsx b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.tsx
index 82e1a64465d..803993a8f01 100644
--- a/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.tsx
+++ b/site/src/pages/DeploymentSettingsPage/SecuritySettingsPage/SecuritySettingsPageView.tsx
@@ -21,11 +21,15 @@ import OptionsTable from "../OptionsTable";
type SecuritySettingsPageViewProps = {
options: SerpentOption[];
+ /** True when the license covers browser-only connections. */
+ isBrowserOnlyEntitled: boolean;
+ /** True when the deployment has browser-only connections turned on. */
featureBrowserOnlyEnabled: boolean;
};
export const SecuritySettingsPageView: FC = ({
options,
+ isBrowserOnlyEntitled,
featureBrowserOnlyEnabled,
}) => {
const tlsOptions = options.filter((o) =>
@@ -75,7 +79,7 @@ export const SecuritySettingsPageView: FC = ({
{featureBrowserOnlyEnabled ? : }
- {!featureBrowserOnlyEnabled ? (
+ {!isBrowserOnlyEntitled ? (