diff --git a/ui/desktop/src/components/settings/app/ExternalBackendSection.tsx b/ui/desktop/src/components/settings/app/ExternalBackendSection.tsx index 408a1a35ac39..7552d5861bf6 100644 --- a/ui/desktop/src/components/settings/app/ExternalBackendSection.tsx +++ b/ui/desktop/src/components/settings/app/ExternalBackendSection.tsx @@ -3,7 +3,7 @@ import { Switch } from '../../ui/switch'; import { Input } from '../../ui/input'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../ui/card'; import { AlertCircle } from 'lucide-react'; -import { ExternalGoosedConfig, defaultSettings } from '../../../utils/settings'; +import { ExternalBackendConfig, defaultSettings } from '../../../utils/settings'; import { defineMessages, useIntl } from '../../../i18n'; import { normalizeAcpHttpBaseUrl } from '../../../acp/url'; @@ -56,12 +56,12 @@ const i18n = defineMessages({ }, certFingerprintHelp: { id: 'externalBackendSection.certFingerprintHelp', - defaultMessage: 'Pin a specific TLS certificate fingerprint. If omitted, the certificate is trusted on first use (TOFU).', + defaultMessage: + 'Pin a specific TLS certificate fingerprint. If omitted, the certificate is trusted on first use (TOFU).', }, restartNote: { id: 'externalBackendSection.restartNote', - defaultMessage: - 'Changes apply to new chat windows. Restart Goose to update existing windows.', + defaultMessage: 'Changes apply to new chat windows. Restart Goose to update existing windows.', }, urlProtocolError: { id: 'externalBackendSection.urlProtocolError', @@ -77,13 +77,14 @@ const i18n = defineMessages({ }, urlBaseError: { id: 'externalBackendSection.urlBaseError', - defaultMessage: 'URL must be the backend base URL before /acp, without query parameters or fragments', + defaultMessage: + 'URL must be the backend base URL before /acp, without query parameters or fragments', }, }); export default function ExternalBackendSection() { const intl = useIntl(); - const [config, setConfig] = useState(defaultSettings.externalGoosed); + const [config, setConfig] = useState(defaultSettings.externalGoosed); const [isSaving, setIsSaving] = useState(false); const [urlError, setUrlError] = useState(null); @@ -95,10 +96,7 @@ export default function ExternalBackendSection() { loadSettings(); }, []); - const validateUrl = ( - value: string, - certFingerprint = config.certFingerprint - ): boolean => { + const validateUrl = (value: string, certFingerprint = config.certFingerprint): boolean => { if (!value) { setUrlError(null); return true; @@ -128,7 +126,7 @@ export default function ExternalBackendSection() { } }; - const saveConfig = async (newConfig: ExternalGoosedConfig): Promise => { + const saveConfig = async (newConfig: ExternalBackendConfig): Promise => { setIsSaving(true); try { await window.electron.setSetting('externalGoosed', newConfig); @@ -139,9 +137,9 @@ export default function ExternalBackendSection() { } }; - const updateField = ( + const updateField = ( field: K, - value: ExternalGoosedConfig[K] + value: ExternalBackendConfig[K] ) => { const newConfig = { ...config, [field]: value }; setConfig(newConfig); @@ -175,14 +173,14 @@ export default function ExternalBackendSection() { {intl.formatMessage(i18n.title)} - - {intl.formatMessage(i18n.description)} - + {intl.formatMessage(i18n.description)}
-

{intl.formatMessage(i18n.useExternalServer)}

+

+ {intl.formatMessage(i18n.useExternalServer)} +

{intl.formatMessage(i18n.useExternalServerDescription)}

diff --git a/ui/desktop/src/i18n/messages/de.json b/ui/desktop/src/i18n/messages/de.json index 1818e3273598..7355e585dede 100644 --- a/ui/desktop/src/i18n/messages/de.json +++ b/ui/desktop/src/i18n/messages/de.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Geheimer Schlüssel" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "Der auf dem goosed-Server konfigurierte geheime Schlüssel (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Der auf dem Goose-Server konfigurierte geheime Schlüssel (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Geben Sie den geheimen Schlüssel des Servers ein" diff --git a/ui/desktop/src/i18n/messages/es.json b/ui/desktop/src/i18n/messages/es.json index e35cc012eb33..6ec9f651e33f 100644 --- a/ui/desktop/src/i18n/messages/es.json +++ b/ui/desktop/src/i18n/messages/es.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Secret Key" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "La secret key configurada en el servidor goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "La clave secreta configurada en el servidor Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Introduce la secret key del servidor" diff --git a/ui/desktop/src/i18n/messages/fr.json b/ui/desktop/src/i18n/messages/fr.json index 30708f4412ee..a1eb8939141a 100644 --- a/ui/desktop/src/i18n/messages/fr.json +++ b/ui/desktop/src/i18n/messages/fr.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Clé secrète" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "La clé secrète configurée sur le serveur goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "La clé secrète configurée sur le serveur Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Saisissez la clé secrète du serveur" diff --git a/ui/desktop/src/i18n/messages/id.json b/ui/desktop/src/i18n/messages/id.json index 68bc48efd2f7..7f5feffb57b8 100644 --- a/ui/desktop/src/i18n/messages/id.json +++ b/ui/desktop/src/i18n/messages/id.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Kunci Rahasia" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "Kunci rahasia yang dikonfigurasi pada server goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Kunci rahasia yang dikonfigurasi pada server Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Masukkan kunci rahasia server" diff --git a/ui/desktop/src/i18n/messages/it.json b/ui/desktop/src/i18n/messages/it.json index eee0676e2780..c6c2cdbbcc70 100644 --- a/ui/desktop/src/i18n/messages/it.json +++ b/ui/desktop/src/i18n/messages/it.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Chiave segreta" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "La chiave segreta configurata sul server goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "La chiave segreta configurata sul server Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Inserisci la chiave segreta del server" diff --git a/ui/desktop/src/i18n/messages/ja.json b/ui/desktop/src/i18n/messages/ja.json index 6fb948ee3b51..a52c123d0221 100644 --- a/ui/desktop/src/i18n/messages/ja.json +++ b/ui/desktop/src/i18n/messages/ja.json @@ -1197,7 +1197,7 @@ "defaultMessage": "シークレットキー" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "goosed サーバーに設定されたシークレットキー(GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Goose サーバーに設定されたシークレットキー(GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "サーバーのシークレットキーを入力" diff --git a/ui/desktop/src/i18n/messages/ko.json b/ui/desktop/src/i18n/messages/ko.json index a2642cdbd798..4a3a36fad2e0 100644 --- a/ui/desktop/src/i18n/messages/ko.json +++ b/ui/desktop/src/i18n/messages/ko.json @@ -1197,7 +1197,7 @@ "defaultMessage": "비밀 키" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "goosed 서버에 설정된 비밀 키 (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Goose 서버에 설정된 비밀 키 (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "서버의 비밀 키를 입력하세요" diff --git a/ui/desktop/src/i18n/messages/ms.json b/ui/desktop/src/i18n/messages/ms.json index 0500ee5377dd..09f0c1324570 100644 --- a/ui/desktop/src/i18n/messages/ms.json +++ b/ui/desktop/src/i18n/messages/ms.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Kunci Rahsia" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "Kunci rahsia yang dikonfigurasikan pada pelayan goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Kunci rahsia yang dikonfigurasikan pada pelayan Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Masukkan kunci rahsia pelayan" diff --git a/ui/desktop/src/i18n/messages/pt.json b/ui/desktop/src/i18n/messages/pt.json index c2e1e51bee6c..a36753fdc683 100644 --- a/ui/desktop/src/i18n/messages/pt.json +++ b/ui/desktop/src/i18n/messages/pt.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Chave secreta" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "A chave secreta configurada no servidor goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "A chave secreta configurada no servidor Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Insira a chave secreta do servidor" diff --git a/ui/desktop/src/i18n/messages/ru.json b/ui/desktop/src/i18n/messages/ru.json index bab350342dfd..9bf1e14288d9 100644 --- a/ui/desktop/src/i18n/messages/ru.json +++ b/ui/desktop/src/i18n/messages/ru.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Секретный ключ" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "Секретный ключ, настроенный на сервере goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Секретный ключ, настроенный на сервере Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Введите секретный ключ сервера" diff --git a/ui/desktop/src/i18n/messages/tr.json b/ui/desktop/src/i18n/messages/tr.json index 6e89f0a6a7f2..377f159c4c1f 100644 --- a/ui/desktop/src/i18n/messages/tr.json +++ b/ui/desktop/src/i18n/messages/tr.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Gizli Anahtar" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "goosed sunucusunda yapılandırılan gizli anahtar (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Goose sunucusunda yapılandırılan gizli anahtar (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Sunucunun gizli anahtarını girin" diff --git a/ui/desktop/src/i18n/messages/vi.json b/ui/desktop/src/i18n/messages/vi.json index bf0a4e5a4ebe..1555eae1bf1a 100644 --- a/ui/desktop/src/i18n/messages/vi.json +++ b/ui/desktop/src/i18n/messages/vi.json @@ -1197,7 +1197,7 @@ "defaultMessage": "Khóa bí mật" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "Khóa bí mật được cấu hình trên máy chủ goosed (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "Khóa bí mật được cấu hình trên máy chủ Goose (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "Nhập khóa bí mật của máy chủ" diff --git a/ui/desktop/src/i18n/messages/zh-CN.json b/ui/desktop/src/i18n/messages/zh-CN.json index 4e84c7146062..2dd5c4b0611c 100644 --- a/ui/desktop/src/i18n/messages/zh-CN.json +++ b/ui/desktop/src/i18n/messages/zh-CN.json @@ -1197,7 +1197,7 @@ "defaultMessage": "密钥" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "在 goosed 服务器上配置的密钥(GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "在 Goose 服务器上配置的密钥(GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "输入服务器的密钥" diff --git a/ui/desktop/src/i18n/messages/zh-TW.json b/ui/desktop/src/i18n/messages/zh-TW.json index 5c42b2432b27..1d846ae9e13c 100644 --- a/ui/desktop/src/i18n/messages/zh-TW.json +++ b/ui/desktop/src/i18n/messages/zh-TW.json @@ -1197,7 +1197,7 @@ "defaultMessage": "密鑰" }, "externalBackendSection.secretKeyHelp": { - "defaultMessage": "在 goosed 伺服器上設定的密鑰 (GOOSE_SERVER__SECRET_KEY)" + "defaultMessage": "在 Goose 伺服器上設定的密鑰 (GOOSE_SERVER__SECRET_KEY)" }, "externalBackendSection.secretKeyPlaceholder": { "defaultMessage": "輸入伺服器的密鑰" diff --git a/ui/desktop/src/startupDiagnostics.test.ts b/ui/desktop/src/startupDiagnostics.test.ts index 87badc8d8df9..ced66a1bf710 100644 --- a/ui/desktop/src/startupDiagnostics.test.ts +++ b/ui/desktop/src/startupDiagnostics.test.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { afterEach, describe, expect, it } from 'vitest'; -import { createGooseServeStartupDiagnostics, createStartupDiagnostics } from './startupDiagnostics'; +import { createGooseServeStartupDiagnostics } from './startupDiagnostics'; const tempDirs: string[] = []; @@ -22,36 +22,6 @@ describe('startup diagnostics', () => { } }); - it('keeps goosed startup diagnostics shape and file prefix', () => { - const diagnosticsDir = makeTempDir(); - const trace = createStartupDiagnostics(diagnosticsDir, '/tmp/project'); - const expectedKeys = [ - 'attemptId', - 'startedAt', - 'goosedPath', - 'workingDir', - 'baseUrl', - 'pid', - 'certFingerprintSeen', - 'healthCheckSucceeded', - 'childExitCode', - 'childExitSignal', - 'stderrTail', - 'events', - ]; - - expect(trace).not.toBeNull(); - expect(path.basename(trace!.diagnosticsPath)).toMatch(/^goosed-startup-.*\.json$/); - expect(Object.keys(trace!.diagnostics)).toEqual(expectedKeys); - expect(trace!.diagnostics).toMatchObject({ - goosedPath: null, - baseUrl: null, - certFingerprintSeen: false, - }); - const saved = JSON.parse(fs.readFileSync(trace!.diagnosticsPath, 'utf8')); - expect(Object.keys(saved)).toEqual(expectedKeys); - }); - it('writes serve startup diagnostics with serve-specific fields', () => { const diagnosticsDir = makeTempDir(); const trace = createGooseServeStartupDiagnostics(diagnosticsDir, '/tmp/project'); diff --git a/ui/desktop/src/startupDiagnostics.ts b/ui/desktop/src/startupDiagnostics.ts index 2e15b25b6c38..46455b8aebcb 100644 --- a/ui/desktop/src/startupDiagnostics.ts +++ b/ui/desktop/src/startupDiagnostics.ts @@ -8,21 +8,6 @@ export interface StartupTraceEvent { details?: Record; } -export interface StartupDiagnostics { - attemptId: string; - startedAt: string; - goosedPath: string | null; - workingDir: string; - baseUrl: string | null; - pid: number | null; - certFingerprintSeen: boolean; - healthCheckSucceeded: boolean; - childExitCode: number | null; - childExitSignal: string | null; - stderrTail: string[]; - events: StartupTraceEvent[]; -} - export interface GooseServeStartupDiagnostics { attemptId: string; startedAt: string; @@ -41,13 +26,6 @@ export interface GooseServeStartupDiagnostics { events: StartupTraceEvent[]; } -export interface StartupTrace { - diagnosticsPath: string; - diagnostics: StartupDiagnostics; - record: (name: string, details?: Record) => void; - flush: () => void; -} - export interface GooseServeStartupTrace { diagnosticsPath: string; diagnostics: GooseServeStartupDiagnostics; @@ -65,27 +43,6 @@ export const appendTail = (target: string[], lines: string[]) => { } }; -const cleanupStartupDiagnostics = (diagnosticsDir: string) => { - const startupLogs = fs - .readdirSync(diagnosticsDir, { withFileTypes: true }) - .filter( - (entry) => - entry.isFile() && entry.name.startsWith('goosed-startup-') && entry.name.endsWith('.json') - ) - .map((entry) => { - const filePath = path.join(diagnosticsDir, entry.name); - return { - filePath, - modifiedMs: fs.statSync(filePath).mtimeMs, - }; - }) - .sort((a, b) => b.modifiedMs - a.modifiedMs); - - for (const startupLog of startupLogs.slice(STARTUP_LOGS_TO_KEEP)) { - fs.unlinkSync(startupLog.filePath); - } -}; - const cleanupGooseServeStartupDiagnostics = (diagnosticsDir: string) => { const startupLogs = fs .readdirSync(diagnosticsDir, { withFileTypes: true }) @@ -109,63 +66,6 @@ const cleanupGooseServeStartupDiagnostics = (diagnosticsDir: string) => { } }; -export const createStartupDiagnostics = ( - diagnosticsDir: string | undefined, - workingDir: string -): StartupTrace | null => { - if (!diagnosticsDir) { - return null; - } - - fs.mkdirSync(diagnosticsDir, { recursive: true }); - cleanupStartupDiagnostics(diagnosticsDir); - const startedAt = new Date(); - const attemptId = `goosed-startup-${startedAt.toISOString().replace(/:/g, '-')}-${process.pid}.json`; - const diagnosticsPath = path.join(diagnosticsDir, attemptId); - const monotonicStart = Date.now(); - - const diagnostics: StartupDiagnostics = { - attemptId, - startedAt: startedAt.toISOString(), - goosedPath: null, - workingDir, - baseUrl: null, - pid: null, - certFingerprintSeen: false, - healthCheckSucceeded: false, - childExitCode: null, - childExitSignal: null, - stderrTail: [], - events: [], - }; - - const flush = () => { - fs.writeFileSync(diagnosticsPath, `${JSON.stringify(diagnostics, null, 2)}\n`); - }; - - const record = (name: string, details?: Record) => { - if (name === 'healthcheck_success') { - diagnostics.healthCheckSucceeded = true; - } - diagnostics.events.push({ - name, - at: new Date().toISOString(), - elapsedMs: Date.now() - monotonicStart, - ...(details ? { details } : {}), - }); - flush(); - }; - - flush(); - - return { - diagnosticsPath, - diagnostics, - record, - flush, - }; -}; - export const createGooseServeStartupDiagnostics = ( diagnosticsDir: string | undefined, workingDir: string diff --git a/ui/desktop/src/utils/__tests__/csp.test.ts b/ui/desktop/src/utils/__tests__/csp.test.ts index 1ea6c427a255..8df2a56c9a8c 100644 --- a/ui/desktop/src/utils/__tests__/csp.test.ts +++ b/ui/desktop/src/utils/__tests__/csp.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect } from 'vitest'; import { buildConnectSrc, shouldUpgradeInsecureRequests, buildCSP } from '../csp'; -import type { ExternalGoosedConfig } from '../settings'; +import type { ExternalBackendConfig } from '../settings'; describe('buildConnectSrc', () => { it('includes default sources when no external backend is configured', () => { @@ -11,7 +11,7 @@ describe('buildConnectSrc', () => { }); it('includes external backend origin when enabled', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'http://dev.company.net:12604', secret: 'test', @@ -22,7 +22,7 @@ describe('buildConnectSrc', () => { }); it('includes external secure WebSocket origin for HTTPS backends', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'https://secure.company.net:12604', secret: 'test', @@ -33,7 +33,7 @@ describe('buildConnectSrc', () => { }); it('does not include external origin when disabled', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: false, url: 'http://dev.company.net:12604', secret: 'test', @@ -43,7 +43,7 @@ describe('buildConnectSrc', () => { }); it('handles invalid URLs gracefully', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'not-a-valid-url', secret: 'test', @@ -60,7 +60,7 @@ describe('shouldUpgradeInsecureRequests', () => { }); it('returns true when external backend is disabled', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: false, url: 'http://dev.company.net:12604', secret: 'test', @@ -69,7 +69,7 @@ describe('shouldUpgradeInsecureRequests', () => { }); it('returns false when external backend uses HTTP', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'http://dev.company.net:12604', secret: 'test', @@ -78,7 +78,7 @@ describe('shouldUpgradeInsecureRequests', () => { }); it('returns true when external backend uses HTTPS', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'https://dev.company.net:12604', secret: 'test', @@ -87,7 +87,7 @@ describe('shouldUpgradeInsecureRequests', () => { }); it('returns true for invalid URLs', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'not-a-url', secret: 'test', @@ -96,7 +96,7 @@ describe('shouldUpgradeInsecureRequests', () => { }); it('returns true when URL is empty', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: '', secret: 'test', @@ -112,7 +112,7 @@ describe('buildCSP', () => { }); it('includes upgrade-insecure-requests with HTTPS external backend', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'https://secure.company.net:12604', secret: 'test', @@ -123,7 +123,7 @@ describe('buildCSP', () => { }); it('excludes upgrade-insecure-requests with HTTP external backend', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'http://dev.company.net:12604', secret: 'test', @@ -134,7 +134,7 @@ describe('buildCSP', () => { }); it('always includes core directives', () => { - const config: ExternalGoosedConfig = { + const config: ExternalBackendConfig = { enabled: true, url: 'http://dev.company.net:12604', secret: 'test', diff --git a/ui/desktop/src/utils/csp.ts b/ui/desktop/src/utils/csp.ts index a2e78ab36149..89b066c2afcd 100644 --- a/ui/desktop/src/utils/csp.ts +++ b/ui/desktop/src/utils/csp.ts @@ -1,4 +1,4 @@ -import type { ExternalGoosedConfig } from './settings'; +import type { ExternalBackendConfig } from './settings'; const DEFAULT_CONNECT_SOURCES = [ "'self'", @@ -15,17 +15,17 @@ const DEFAULT_CONNECT_SOURCES = [ 'https://objects.githubusercontent.com', ]; -export function buildConnectSrc(externalGoosed?: ExternalGoosedConfig): string { +export function buildConnectSrc(externalBackend?: ExternalBackendConfig): string { const sources = [...DEFAULT_CONNECT_SOURCES]; - if (externalGoosed?.enabled && externalGoosed.url) { + if (externalBackend?.enabled && externalBackend.url) { try { - const externalUrl = new URL(externalGoosed.url); + const externalUrl = new URL(externalBackend.url); sources.push(externalUrl.origin); externalUrl.protocol = externalUrl.protocol === 'https:' ? 'wss:' : 'ws:'; sources.push(externalUrl.origin); } catch { - console.warn('Invalid external goosed URL in settings, skipping CSP entry'); + console.warn('Invalid external backend URL in settings, skipping CSP entry'); } } @@ -43,22 +43,22 @@ export function buildConnectSrc(externalGoosed?: ExternalGoosedConfig): string { * Loopback addresses (127.0.0.1 / localhost) are exempt from the upgrade * per the CSP spec, which is why the built-in local backend is unaffected. */ -export function shouldUpgradeInsecureRequests(externalGoosed?: ExternalGoosedConfig): boolean { - if (!externalGoosed?.enabled || !externalGoosed.url) { +export function shouldUpgradeInsecureRequests(externalBackend?: ExternalBackendConfig): boolean { + if (!externalBackend?.enabled || !externalBackend.url) { return true; } try { - const parsed = new URL(externalGoosed.url); + const parsed = new URL(externalBackend.url); return parsed.protocol !== 'http:'; } catch { return true; } } -export function buildCSP(externalGoosed?: ExternalGoosedConfig): string { - const connectSrc = buildConnectSrc(externalGoosed); - const upgradeDirective = shouldUpgradeInsecureRequests(externalGoosed) +export function buildCSP(externalBackend?: ExternalBackendConfig): string { + const connectSrc = buildConnectSrc(externalBackend); + const upgradeDirective = shouldUpgradeInsecureRequests(externalBackend) ? 'upgrade-insecure-requests;' : ''; diff --git a/ui/desktop/src/utils/settings.ts b/ui/desktop/src/utils/settings.ts index 9f94d301c927..31e405d8333c 100644 --- a/ui/desktop/src/utils/settings.ts +++ b/ui/desktop/src/utils/settings.ts @@ -1,4 +1,4 @@ -export interface ExternalGoosedConfig { +export interface ExternalBackendConfig { enabled: boolean; url: string; secret: string; @@ -36,7 +36,8 @@ export interface Settings { enableWakelock: boolean; enableNotifications: boolean; spellcheckEnabled: boolean; - externalGoosed: ExternalGoosedConfig; + // Key is kept as `externalGoosed` for backward compat with persisted user settings. + externalGoosed: ExternalBackendConfig; globalShortcut?: string | null; keyboardShortcuts: KeyboardShortcuts; diff --git a/ui/desktop/src/utils/winShims.ts b/ui/desktop/src/utils/winShims.ts index 7b8170dadd21..e4dca0616ecc 100644 --- a/ui/desktop/src/utils/winShims.ts +++ b/ui/desktop/src/utils/winShims.ts @@ -20,7 +20,7 @@ export async function ensureWinShims(): Promise { try { await fs.promises.mkdir(tgtDir, { recursive: true }); - // Copy command-line tools, NOT goosed.exe (which should always be used locally) + // Copy command-line tools only; the goose binary is never shimmed const shims = ['uvx.exe', 'uv.exe', 'npx.cmd']; await Promise.all(