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 ? (