feat(FN-2585): remove top-level remote access toggle

- Remove the standalone remoteEnabled setting from CLI, core settings defaults/types, and dashboard settings APIs/UI
- Treat remote access as enabled when an active provider is selected and that provider is configured as enabled
- Update remote auth and engine lifecycle checks to gate on provider activation instead of a global flag
- Adjust tests and add a changeset documenting the remote access configuration simplification
This commit is contained in:
Fusion
2026-04-26 09:19:03 -07:00
committed by gsxdsm
parent 5450080d45
commit 4379922cc8
19 changed files with 26 additions and 57 deletions

View File

@@ -75,7 +75,6 @@ async function REQUEST(
describe("remote access headless parity", () => {
function buildRemoteAccessSettings() {
return {
enabled: true,
activeProvider: "cloudflare" as const,
providers: {
tailscale: {

View File

@@ -8,7 +8,6 @@ import { request as performRequest } from "../test-request.js";
function buildRemoteAccessSettings(overrides: Record<string, unknown> = {}) {
return {
enabled: true,
activeProvider: "cloudflare" as const,
providers: {
tailscale: {

View File

@@ -14,7 +14,6 @@ import {
function createRemoteSettings(overrides: Partial<RemoteAccessProjectSettings> = {}): RemoteAccessProjectSettings {
return {
enabled: true,
activeProvider: "tailscale",
providers: {
tailscale: {
@@ -94,7 +93,7 @@ describe("remote-auth", () => {
});
it("returns disabled when remote access or token strategy is disabled", () => {
const disabledRemote = validateRemoteAuthToken("anything", createRemoteSettings({ enabled: false }));
const disabledRemote = validateRemoteAuthToken("anything", createRemoteSettings({ activeProvider: null }));
expect(disabledRemote).toEqual({ status: "disabled" });
const disabledStrategies = validateRemoteAuthToken(

View File

@@ -8,7 +8,6 @@ import { request as performRequest } from "../test-request.js";
function buildRemoteAccessSettings() {
return {
enabled: true,
activeProvider: "cloudflare" as const,
providers: {
tailscale: {

View File

@@ -13670,7 +13670,6 @@ describe("GET /settings/scopes", () => {
global: { themeMode: "dark" },
project: {
remoteAccess: {
enabled: true,
activeProvider: "tailscale",
providers: {
tailscale: {

View File

@@ -110,12 +110,16 @@ function isRemoteAccessTokenStrategyEnabled(settings: RemoteAccessSettings): boo
return settings.tokenStrategy.persistent.enabled || settings.tokenStrategy.shortLived.enabled;
}
function isRemoteProviderEnabled(settings: RemoteAccessSettings): boolean {
return Boolean(settings.activeProvider != null && settings.providers[settings.activeProvider]?.enabled);
}
export function validateRemoteAuthToken(
rt: string | null | undefined,
settings: RemoteAccessSettings,
nowMs: number = Date.now(),
): RemoteTokenValidationResult {
if (!settings.enabled || !isRemoteAccessTokenStrategyEnabled(settings)) {
if (!isRemoteProviderEnabled(settings) || !isRemoteAccessTokenStrategyEnabled(settings)) {
return { status: "disabled" };
}

View File

@@ -122,8 +122,8 @@ export function registerSettingsMemoryRoutes(ctx: ApiRoutesContext, deps: Settin
const settings = await scopedStore.getSettings();
const remoteAccess = settings.remoteAccess;
if (!remoteAccess?.enabled) {
throw new ApiError(409, "Remote access is disabled", { code: "REMOTE_ACCESS_DISABLED" });
if (!remoteAccess || remoteAccess.activeProvider == null || !remoteAccess.providers[remoteAccess.activeProvider]?.enabled) {
throw new ApiError(409, "No remote provider is enabled", { code: "REMOTE_ACCESS_DISABLED" });
}
const baseUrl = resolveRemoteBaseUrl(remoteAccess);
@@ -266,7 +266,8 @@ export function registerSettingsMemoryRoutes(ctx: ApiRoutesContext, deps: Settin
function toRemoteSettingsPayload(remoteAccess: NonNullable<Awaited<ReturnType<typeof store.getSettings>>["remoteAccess"]>) {
const persistentToken = remoteAccess.tokenStrategy.persistent.token?.trim() ?? "";
return {
remoteEnabled: Boolean(remoteAccess.enabled),
remoteEnabled: remoteAccess.activeProvider != null &&
(remoteAccess.providers[remoteAccess.activeProvider]?.enabled ?? false),
remoteActiveProvider: remoteAccess.activeProvider ?? null,
remoteTailscaleEnabled: Boolean(remoteAccess.providers.tailscale.enabled),
remoteTailscaleHostname: remoteAccess.providers.tailscale.hostname,
@@ -315,7 +316,6 @@ export function registerSettingsMemoryRoutes(ctx: ApiRoutesContext, deps: Settin
const body = (req.body ?? {}) as Record<string, unknown>;
const nextRemoteAccess = {
...remoteAccess,
enabled: body.remoteEnabled === undefined ? remoteAccess.enabled : Boolean(body.remoteEnabled),
activeProvider: body.remoteActiveProvider === undefined
? remoteAccess.activeProvider
: (body.remoteActiveProvider as "tailscale" | "cloudflare" | null),