Gate default relay auto-connect behind release flag (#2589)

Signed-off-by: npub1cl47vfhsqpqy9pwndphpm36vcp7vvz5h2js4qpqm5yewzj7nutkq7xyw8c <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
Co-authored-by: Bradley Axen <baxen@squareup.com>
Co-authored-by: npub1cl47vfhsqpqy9pwndphpm36vcp7vvz5h2js4qpqm5yewzj7nutkq7xyw8c <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
This commit is contained in:
Wes
2026-07-23 14:59:10 -06:00
committed by GitHub
parent f3f7688c3a
commit e67303f603
11 changed files with 263 additions and 28 deletions

View File

@@ -211,12 +211,19 @@ desktop-tauri-test-compiled-flags: _ensure-sidecar-stubs
cd desktop/src-tauri
echo "=== Clean build (no flag) → expect false ==="
env -u BUZZ_BUILD_OBSERVER_ARCHIVE_DEFAULT \
-u BUZZ_BUILD_AUTO_CONNECT_DEFAULT_RELAY \
BUZZ_TEST_EXPECTED_OBSERVER_ARCHIVE_DEFAULT=false \
cargo test observer_archive_default_enabled_matches_expected -- --ignored --nocapture
echo "=== Internal build (flag set) → expect true ==="
env -u BUZZ_BUILD_AUTO_CONNECT_DEFAULT_RELAY \
BUZZ_TEST_EXPECTED_AUTO_CONNECT_DEFAULT_RELAY=false \
cargo test compiled_flag_matches_expected -- --ignored --nocapture
echo "=== Internal build (flags set) → expect true ==="
BUZZ_BUILD_OBSERVER_ARCHIVE_DEFAULT=1 \
BUZZ_TEST_EXPECTED_OBSERVER_ARCHIVE_DEFAULT=true \
cargo test observer_archive_default_enabled_matches_expected -- --ignored --nocapture
BUZZ_BUILD_AUTO_CONNECT_DEFAULT_RELAY=1 \
BUZZ_TEST_EXPECTED_AUTO_CONNECT_DEFAULT_RELAY=true \
cargo test compiled_flag_matches_expected -- --ignored --nocapture
echo "Both compiled states verified."
# Build the full desktop Tauri app locally (unsigned, for testing)

View File

@@ -15,6 +15,7 @@ fn main() {
println!("cargo:rerun-if-env-changed=BUZZ_BUILD_RELAY_RECONNECT_CMD");
println!("cargo:rerun-if-env-changed=BUZZ_BUILD_OBSERVER_ARCHIVE_DEFAULT");
println!("cargo:rerun-if-env-changed=BUZZ_BUILD_AGENT_METRIC_ARCHIVE_DEFAULT");
println!("cargo:rerun-if-env-changed=BUZZ_BUILD_AUTO_CONNECT_DEFAULT_RELAY");
println!("cargo:rustc-check-cfg=cfg(buzz_updater_enabled)");
if let Ok(relay_url) = std::env::var("BUZZ_RELAY_URL") {
@@ -89,6 +90,13 @@ fn main() {
println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_AGENT_METRIC_ARCHIVE_DEFAULT=1");
}
// Presence-only release capability: internal desktop builds opt into
// auto-connecting their configured default relay on first run. OSS builds
// leave this unset and retain explicit community selection.
if std::env::var("BUZZ_BUILD_AUTO_CONNECT_DEFAULT_RELAY").is_ok() {
println!("cargo:rustc-env=BUZZ_DESKTOP_BUILD_AUTO_CONNECT_DEFAULT_RELAY=1");
}
let updater_public_key = std::env::var("BUZZ_UPDATER_PUBLIC_KEY")
.ok()
.map(|value| value.trim().to_string())

View File

@@ -54,6 +54,27 @@ pub fn get_default_relay_url() -> String {
relay::relay_ws_url()
}
#[tauri::command]
pub fn auto_connect_default_relay_enabled() -> bool {
option_env!("BUZZ_DESKTOP_BUILD_AUTO_CONNECT_DEFAULT_RELAY").is_some()
}
#[cfg(test)]
mod auto_connect_default_relay_tests {
use super::auto_connect_default_relay_enabled;
#[test]
#[ignore]
fn compiled_flag_matches_expected() {
let expected = std::env::var("BUZZ_TEST_EXPECTED_AUTO_CONNECT_DEFAULT_RELAY")
.expect("compiled-flag test requires an expected value");
assert_eq!(
auto_connect_default_relay_enabled(),
expected == "true" || expected == "1"
);
}
}
#[tauri::command]
pub fn is_shared_identity() -> bool {
std::env::var("BUZZ_SHARE_IDENTITY")

View File

@@ -692,6 +692,7 @@ pub fn run() {
get_presence,
get_os_idle_seconds,
get_default_relay_url,
auto_connect_default_relay_enabled,
get_legacy_workspace_storage,
is_shared_identity,
get_relay_ws_url,

View File

@@ -3,12 +3,15 @@ import test from "node:test";
import {
clearCommunityStorage,
initFirstCommunity,
migrateLegacyCommunityStorage,
shouldAutoConnectDefaultRelay,
} from "./communityStorage.ts";
function createMemoryStorage(initial = {}) {
const values = new Map(Object.entries(initial));
return {
values,
getItem: (key) => values.get(key) ?? null,
setItem: (key, value) => values.set(key, String(value)),
removeItem: (key) => values.delete(key),
@@ -46,6 +49,46 @@ test("migrateLegacyCommunityStorage does not overwrite new community state", ()
assert.equal(storage.getItem("buzz-active-community-id"), "new");
});
test("signed-build relay defaults auto-connect during first-run onboarding", () => {
assert.equal(
shouldAutoConnectDefaultRelay("wss://buzz.block.builderlab.xyz"),
true,
);
assert.equal(shouldAutoConnectDefaultRelay("ws://localhost:3000"), false);
assert.equal(shouldAutoConnectDefaultRelay("ws://127.0.0.1:3000"), false);
assert.equal(shouldAutoConnectDefaultRelay("ws://[::1]:3000"), false);
assert.equal(shouldAutoConnectDefaultRelay("ws://0.0.0.0:3000"), false);
assert.equal(shouldAutoConnectDefaultRelay("http://localhost:3000"), false);
assert.equal(
shouldAutoConnectDefaultRelay("https://relay.example.com"),
false,
);
assert.equal(shouldAutoConnectDefaultRelay("relay.example.com"), false);
assert.equal(shouldAutoConnectDefaultRelay("not a valid relay"), false);
});
test("failed first-community write preserves existing community data", () => {
const storage = createMemoryStorage({
"buzz-communities": '[{"id":"existing"}]',
"buzz-workspaces": '[{"id":"legacy"}]',
"buzz-active-workspace-id": "legacy",
});
storage.setItem = (key, value) => {
if (key === "buzz-communities") {
throw new Error("QuotaExceededError");
}
storage.values.set(key, String(value));
};
globalThis.localStorage = storage;
globalThis.window = { localStorage: storage };
assert.equal(initFirstCommunity("wss://relay.example.com", "pubkey"), null);
assert.equal(storage.getItem("buzz-communities"), '[{"id":"existing"}]');
assert.equal(storage.getItem("buzz-active-community-id"), null);
assert.equal(storage.getItem("buzz-workspaces"), '[{"id":"legacy"}]');
assert.equal(storage.getItem("buzz-active-workspace-id"), "legacy");
});
test("clearCommunityStorage removes new and legacy state", () => {
const storage = createMemoryStorage({
"buzz-communities": "new",

View File

@@ -81,8 +81,11 @@ export function loadCommunities(): Community[] {
}
}
export function saveCommunities(communities: Community[]): void {
setLocalStorageItemWithRecovery(COMMUNITIES_KEY, JSON.stringify(communities));
export function saveCommunities(communities: Community[]): boolean {
return setLocalStorageItemWithRecovery(
COMMUNITIES_KEY,
JSON.stringify(communities),
);
}
export function clearCommunityStorage(storage: Storage = localStorage): void {
@@ -97,8 +100,8 @@ export function loadActiveCommunityId(): string | null {
return localStorage.getItem(ACTIVE_COMMUNITY_KEY);
}
export function saveActiveCommunityId(id: string): void {
setLocalStorageItemWithRecovery(ACTIVE_COMMUNITY_KEY, id);
export function saveActiveCommunityId(id: string): boolean {
return setLocalStorageItemWithRecovery(ACTIVE_COMMUNITY_KEY, id);
}
export function normalizeRelayUrl(url: string): string {
@@ -108,13 +111,29 @@ export function normalizeRelayUrl(url: string): string {
return url;
}
function isLocalRelayHost(hostname: string): boolean {
return ["localhost", "127.0.0.1", "[::1]", "0.0.0.0"].includes(hostname);
}
export function shouldAutoConnectDefaultRelay(relayUrl: string): boolean {
try {
const parsed = new URL(relayUrl);
return (
(parsed.protocol === "ws:" || parsed.protocol === "wss:") &&
!isLocalRelayHost(parsed.hostname)
);
} catch {
return false;
}
}
export function deriveCommunityName(relayUrl: string): string {
try {
const url = new URL(
relayUrl.replace("ws://", "http://").replace("wss://", "https://"),
);
const host = url.hostname;
if (host === "localhost" || host === "127.0.0.1") {
if (isLocalRelayHost(host)) {
return "Local Dev";
}
const parts = host.split(".");
@@ -136,17 +155,40 @@ export function initFirstCommunity(
relayUrl: string,
pubkey: string,
name?: string,
): Community {
): Community | null {
const normalizedUrl = normalizeRelayUrl(relayUrl);
const trimmedName = name?.trim();
const community: Community = {
id: crypto.randomUUID(),
name: trimmedName || deriveCommunityName(normalizedUrl),
relayUrl: normalizedUrl,
// Compiled default relays must admit the first token-less connection; there
// is no invite-token prompt on this auto-connect path.
pubkey,
addedAt: new Date().toISOString(),
};
saveCommunities([community]);
saveActiveCommunityId(community.id);
const previousActiveCommunityId = localStorage.getItem(ACTIVE_COMMUNITY_KEY);
const didSaveActiveCommunity = saveActiveCommunityId(community.id);
if (!didSaveActiveCommunity) {
return null;
}
if (!saveCommunities([community])) {
// A failed setItem leaves the existing communities value untouched. Roll
// back only the active-ID write so inconsistent pre-existing data is never
// destroyed while recovering from a quota failure.
try {
if (previousActiveCommunityId === null) {
localStorage.removeItem(ACTIVE_COMMUNITY_KEY);
} else {
localStorage.setItem(ACTIVE_COMMUNITY_KEY, previousActiveCommunityId);
}
} catch {
// Best effort: persistence is already unavailable, and callers will stay
// on setup instead of reloading.
}
return null;
}
return community;
}

View File

@@ -2,7 +2,11 @@ import { useEffect, useRef, useState } from "react";
import { relayClient } from "@/shared/api/relayClient";
import { resetRateLimitGate } from "@/shared/api/relayRateLimitGate";
import { applyCommunity, getDefaultRelayUrl } from "@/shared/api/tauri";
import {
applyCommunity,
autoConnectDefaultRelayEnabled,
getDefaultRelayUrl,
} from "@/shared/api/tauri";
import { getIdentity } from "@/shared/api/tauriIdentity";
import { getOverrides } from "@/shared/features";
import { resetMediaCaches } from "@/shared/lib/mediaUrl";
@@ -25,7 +29,10 @@ import { resetSidebarRelayConnectionCardState } from "@/features/sidebar/ui/useS
import { clearMarkdownNodeCache } from "@/shared/ui/markdown/nodeCache";
import { resetVideoPlayerState } from "@/shared/ui/videoPlayerState";
import { initFirstCommunity } from "./communityStorage";
import {
initFirstCommunity,
shouldAutoConnectDefaultRelay,
} from "./communityStorage";
import type { Community } from "./types";
/**
@@ -107,13 +114,33 @@ export function useCommunityInit(
if (!activeCommunity) {
try {
const defaultRelayUrl = await getDefaultRelayUrl();
const autoConnectDefaultRelay =
await autoConnectDefaultRelayEnabled();
if (isSharedIdentity) {
// Internal builds explicitly opt into treating their reviewed default
// relay as the first community. Public builds retain community
// selection even when BUZZ_RELAY_URL is overridden at runtime.
if (
isSharedIdentity ||
(autoConnectDefaultRelay &&
shouldAutoConnectDefaultRelay(defaultRelayUrl))
) {
const identity = await getIdentity();
if (cancelled) return;
initFirstCommunity(defaultRelayUrl, identity.pubkey);
if (!cancelled) {
const community = initFirstCommunity(
defaultRelayUrl,
identity.pubkey,
);
if (community && !cancelled) {
window.location.reload();
return;
}
if (!cancelled) {
setResult({
isReady: false,
needsSetup: true,
defaultRelayUrl,
});
}
return;
}

View File

@@ -359,6 +359,10 @@ export function getDefaultRelayUrl(): Promise<string> {
return invokeTauri<string>("get_default_relay_url");
}
export function autoConnectDefaultRelayEnabled(): Promise<boolean> {
return invokeTauri<boolean>("auto_connect_default_relay_enabled");
}
export function isSharedIdentity(): Promise<boolean> {
return invokeTauri<boolean>("is_shared_identity");
}

View File

@@ -417,6 +417,7 @@ type E2eConfig = {
};
relayHttpUrl?: string;
relayWsUrl?: string;
autoConnectDefaultRelay?: boolean;
identity?: TestIdentity;
};
@@ -9816,6 +9817,8 @@ export function maybeInstallE2eTauriMocks() {
return getRelayWsUrl(activeConfig);
case "get_default_relay_url":
return getRelayWsUrl(activeConfig);
case "auto_connect_default_relay_enabled":
return activeConfig?.autoConnectDefaultRelay ?? false;
case "get_legacy_workspace_storage":
return {
workspaces: null,

View File

@@ -621,7 +621,32 @@ test("first-launch key import continues to machine setup", async ({ page }) => {
await expect(page.getByTestId("app-loading-gate")).toHaveCount(0);
});
test("first-community choices route join, create, owner, and member intents", async ({
test("non-local runtime override keeps community selection without release flag", async ({
page,
}) => {
await seedActiveIdentity(page, BLANK_TYLER_IDENTITY);
await page.addInitScript((pubkey) => {
window.localStorage.setItem(
`buzz-machine-onboarding-complete.v2:${pubkey}`,
"true",
);
}, BLANK_TYLER_IDENTITY.pubkey);
await installMockBridge(page, undefined, {
relayWsUrl: "wss://override.example.com",
skipOnboardingSeed: true,
skipCommunitySeed: true,
});
await page.goto("/");
await expect(
page.getByRole("button", { name: /Join a community/ }),
).toBeVisible();
await expect
.poll(() => page.evaluate(() => localStorage.getItem("buzz-communities")))
.toBeNull();
});
test("non-local default auto-connects when the release flag is enabled", async ({
page,
}) => {
await seedActiveIdentity(page, BLANK_TYLER_IDENTITY);
@@ -633,6 +658,47 @@ test("first-community choices route join, create, owner, and member intents", as
}, BLANK_TYLER_IDENTITY.pubkey);
await installMockBridge(page, undefined, {
relayWsUrl: "wss://default.example.com",
autoConnectDefaultRelay: true,
skipOnboardingSeed: true,
skipCommunitySeed: true,
});
await page.goto("/");
await expectIncompleteOnboarding(page);
await expect
.poll(() =>
page.evaluate(() => {
const raw = window.localStorage.getItem("buzz-communities");
const communities = raw
? (JSON.parse(raw) as Array<{ id: string; relayUrl: string }>)
: [];
return {
activeMatchesCommunity:
communities.length === 1 &&
window.localStorage.getItem("buzz-active-community-id") ===
communities[0]?.id,
relayUrl: communities[0]?.relayUrl ?? null,
};
}),
)
.toEqual({
activeMatchesCommunity: true,
relayUrl: "wss://default.example.com",
});
});
test("first-community choices route join, create, owner, and member intents", async ({
page,
}) => {
await seedActiveIdentity(page, BLANK_TYLER_IDENTITY);
await page.addInitScript((pubkey) => {
window.localStorage.setItem(
`buzz-machine-onboarding-complete.v2:${pubkey}`,
"true",
);
}, BLANK_TYLER_IDENTITY.pubkey);
await installMockBridge(page, undefined, {
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
});
@@ -718,7 +784,7 @@ test("first-community owner can connect an existing hosted community", async ({
],
},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -776,7 +842,7 @@ test("first-community owner can create and connect a hosted community", async ({
page,
{},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -850,7 +916,7 @@ test("hosted community address line stays within the card for a long name", asyn
page,
{},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -921,7 +987,7 @@ test("first-community reports a created community without a relay address", asyn
},
},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -952,7 +1018,7 @@ test("first-community X cancels a pending sign-in", async ({ page }) => {
page,
{ builderlabLoginDelayMs: 5_000 },
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -994,7 +1060,7 @@ test("first-community owner can replace a mismatched account identity", async ({
builderlabIdentity: { pubkey_hex: "f".repeat(64) },
},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -1044,7 +1110,7 @@ test("first-community explains when the local identity belongs to another accoun
builderlabBindError: { code: "pubkey_already_bound" },
},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -1085,7 +1151,7 @@ test("back clears Builderlab auth before returning to first-community choices",
builderlabIdentity: { pubkey_hex: BLANK_TYLER_IDENTITY.pubkey },
},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -1173,7 +1239,7 @@ test("first-community direct join reaches profile", async ({ page }) => {
);
}, BLANK_TYLER_IDENTITY.pubkey);
await installMockBridge(page, undefined, {
relayWsUrl: "wss://onboarding.communities.buzz.xyz",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
});
@@ -1228,7 +1294,7 @@ test("first-community direct join cancel returns to request access", async ({
page,
{ applyCommunityDelayMs: 5_000 },
{
relayWsUrl: "wss://onboarding.communities.buzz.xyz",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
skipCommunitySeed: true,
},
@@ -1359,7 +1425,7 @@ test("connected first-community profile step offers equal-width Next and Back co
id: "txn-profile-step",
source: "first-community",
stage: "profile",
relayUrl: "wss://default.example.com",
relayUrl: "ws://localhost:3000",
communityName: "Default",
communityId: "e2e-default-community",
addedCommunity: true,
@@ -1407,7 +1473,7 @@ test("connected first-community profile step offers equal-width Next and Back co
],
},
{
relayWsUrl: "wss://default.example.com",
relayWsUrl: "ws://localhost:3000",
skipOnboardingSeed: true,
},
);

View File

@@ -461,6 +461,7 @@ type BridgeOptions = {
mock?: MockBridgeOptions;
relayHttpUrl?: string;
relayWsUrl?: string;
autoConnectDefaultRelay?: boolean;
skipOnboardingSeed?: boolean;
skipCommunitySeed?: boolean;
/**
@@ -712,7 +713,14 @@ export async function installBridge(page: Page, options: BridgeOptions) {
}
await page.addInitScript(
({ identity: bridgeIdentity, mock, mode, relayHttpUrl, relayWsUrl }) => {
({
identity: bridgeIdentity,
mock,
mode,
relayHttpUrl,
relayWsUrl,
autoConnectDefaultRelay,
}) => {
const notificationLog: Array<{
body: string | null;
title: string;
@@ -769,6 +777,8 @@ export async function installBridge(page: Page, options: BridgeOptions) {
mode,
relayHttpUrl: relayHttpUrl ?? currentConfig.relayHttpUrl,
relayWsUrl: relayWsUrl ?? currentConfig.relayWsUrl,
autoConnectDefaultRelay:
autoConnectDefaultRelay ?? currentConfig.autoConnectDefaultRelay,
};
testWindow.__BUZZ_E2E_APP_BADGE_COUNT__ = 0;
testWindow.__BUZZ_E2E_APP_BADGE_STATE__ = "none";
@@ -791,6 +801,7 @@ export async function installBridge(page: Page, options: BridgeOptions) {
mode: options.mode,
relayHttpUrl: options.relayHttpUrl,
relayWsUrl: options.relayWsUrl,
autoConnectDefaultRelay: options.autoConnectDefaultRelay,
},
);
}
@@ -800,6 +811,7 @@ export async function installMockBridge(
mock?: MockBridgeOptions,
options?: {
relayWsUrl?: string;
autoConnectDefaultRelay?: boolean;
skipOnboardingSeed?: boolean;
skipCommunitySeed?: boolean;
seedPreviewFeatures?: boolean;
@@ -809,6 +821,7 @@ export async function installMockBridge(
mode: "mock",
mock,
relayWsUrl: options?.relayWsUrl,
autoConnectDefaultRelay: options?.autoConnectDefaultRelay,
skipOnboardingSeed: options?.skipOnboardingSeed,
skipCommunitySeed: options?.skipCommunitySeed,
seedPreviewFeatures: options?.seedPreviewFeatures,