From 525fd852c2133b72279dc3e1645d272dfb6e203a Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sat, 24 Oct 2026 07:32:11 +0000 Subject: [PATCH 1/4] test(cli): use a globally routable IPv6 address in the public bind spec 2001:db8::/32 is the IPv6 documentation prefix and is now classed as non-public, so the bind is trusted and the spec failed. Use a public address from 2606:4700:4700::/48 instead. --- core/cli/run_safety_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/cli/run_safety_test.go b/core/cli/run_safety_test.go index 21bcd3d87a94..1155e23e0167 100644 --- a/core/cli/run_safety_test.go +++ b/core/cli/run_safety_test.go @@ -88,7 +88,7 @@ var _ = Describe("requireAuthOrTrustedBind", func() { }) It("rejects public IPv6", func() { - Expect(requireAuthOrTrustedBind("[2001:db8::1]:8080", false, false)).To(HaveOccurred()) + Expect(requireAuthOrTrustedBind("[2606:4700:4700::1111]:8080", false, false)).To(HaveOccurred()) }) }) From 369e65a342d40225e73342ce8fcb754b35ba4c22 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sat, 24 Oct 2026 07:31:57 +0000 Subject: [PATCH 2/4] fix(addons): rename installFlow.js so it no longer clashes with InstallFlow.jsx installFlow.js and InstallFlow.jsx differ only by case. On a case-insensitive filesystem the bundler can resolve `import FlowStatus from './InstallFlow'` to the .js module, which has no default export, and the macOS build fails with MISSING_EXPORT. Rename the module to installAndTurnOn.js, after its main export, and update its two importers. No code changes. Assisted-by: Claude Code:claude-sonnet-5-5 --- .../components/addons/{installFlow.js => installAndTurnOn.js} | 0 core/http/react-ui/src/components/addons/useAddonActions.js | 2 +- core/http/react-ui/tests/unit/addons.test.mjs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename core/http/react-ui/src/components/addons/{installFlow.js => installAndTurnOn.js} (100%) diff --git a/core/http/react-ui/src/components/addons/installFlow.js b/core/http/react-ui/src/components/addons/installAndTurnOn.js similarity index 100% rename from core/http/react-ui/src/components/addons/installFlow.js rename to core/http/react-ui/src/components/addons/installAndTurnOn.js diff --git a/core/http/react-ui/src/components/addons/useAddonActions.js b/core/http/react-ui/src/components/addons/useAddonActions.js index cfdc8d18a06b..e94d0fbd5606 100644 --- a/core/http/react-ui/src/components/addons/useAddonActions.js +++ b/core/http/react-ui/src/components/addons/useAddonActions.js @@ -1,7 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' import { createActionBook, effectOutcome } from './actionBook' import { runLifecycle, settleOperation } from './lifecycleFlow' -import { runInstallAndTurnOn } from './installFlow' +import { runInstallAndTurnOn } from './installAndTurnOn' // Runs user actions that change an add-on, one operation identity per action. // diff --git a/core/http/react-ui/tests/unit/addons.test.mjs b/core/http/react-ui/tests/unit/addons.test.mjs index 9a572a350f54..10dc708c4f78 100644 --- a/core/http/react-ui/tests/unit/addons.test.mjs +++ b/core/http/react-ui/tests/unit/addons.test.mjs @@ -17,7 +17,7 @@ import { runLifecycle, settleOperation } from '../../src/components/addons/lifec import { createActionBook, effectOutcome } from '../../src/components/addons/actionBook.js' import { describeError, describeOutcome } from '../../src/components/addons/errors.js' import { backendState, libraryOrigin, shortDigest as shortBackendDigest } from '../../src/utils/backendRows.js' -import { runInstallAndTurnOn } from '../../src/components/addons/installFlow.js' +import { runInstallAndTurnOn } from '../../src/components/addons/installAndTurnOn.js' import { installSteps, STEP_ORDER } from '../../src/components/addons/installSteps.js' const json = (status, body) => ({ ok: status >= 200 && status < 300, status, json: async () => body }) From 15fdbd3abf81e7a9c25e64b6341d8ecd1204b5a2 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sat, 24 Oct 2026 07:40:07 +0000 Subject: [PATCH 3/4] fix(addons): keep Reload on the page of an add-on that is turned off The clearer empty states for a stopped add-on dropped the Reload button from the unavailable page, so a user who turned the add-on back on had no way to mount it again without leaving the page. Render the button in the actions of the off state, next to Turn on. --- core/http/react-ui/src/addons/AddonRoute.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/core/http/react-ui/src/addons/AddonRoute.jsx b/core/http/react-ui/src/addons/AddonRoute.jsx index d005b95c6202..5bf1979ae825 100644 --- a/core/http/react-ui/src/addons/AddonRoute.jsx +++ b/core/http/react-ui/src/addons/AddonRoute.jsx @@ -181,6 +181,7 @@ export default function AddonRoute() { {t('apps.start')} )} + {extra} {outcome && outcome.outcome && describeOutcome(outcome.outcome, t, outcome.error) && ( {describeOutcome(outcome.outcome, t, outcome.error)} )} From 9399c6986dec8fcc0871f7e8422642c14000037e Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sat, 24 Oct 2026 07:40:07 +0000 Subject: [PATCH 4/4] test(ui): serve the Voice add-on in the diarization profiles spec The remembered voices link now opens the page of the Voice add-on, which the core build no longer draws. Install the built Voice bundle next to Studio, as the other specs do for their add-ons, and build it in the global setup. --- core/http/react-ui/e2e/diarization-profiles.spec.js | 5 +++-- core/http/react-ui/e2e/studio-addon.js | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/http/react-ui/e2e/diarization-profiles.spec.js b/core/http/react-ui/e2e/diarization-profiles.spec.js index 2bb00ea4950f..3adc70fba027 100644 --- a/core/http/react-ui/e2e/diarization-profiles.spec.js +++ b/core/http/react-ui/e2e/diarization-profiles.spec.js @@ -27,8 +27,9 @@ async function setup(page, permission = true, diarizationPermission = true) { return route.fulfill({ json: data }) }) await page.route('**/v1/audio/diarization', route => route.fulfill({ json: result })) - // Studio is an add-on. Installed after the catch-all above, so its routes win. - await installStudioAddons(page, { ids: ['studio'] }) + // Studio and Voice are add-ons. Installed after the catch-all above, so their routes win. + // The remembered-voices link opens the Voice add-on page. + await installStudioAddons(page, { ids: ['studio', 'voice'] }) await page.goto('/app/diarization') if (!diarizationPermission) return await expect(page.getByRole('button', { name: 'diarizer', exact: true })).toBeVisible() diff --git a/core/http/react-ui/e2e/studio-addon.js b/core/http/react-ui/e2e/studio-addon.js index e2efd995ab89..3565355e9896 100644 --- a/core/http/react-ui/e2e/studio-addon.js +++ b/core/http/react-ui/e2e/studio-addon.js @@ -24,9 +24,9 @@ export async function buildAddonBundles(ids) { for (const id of ids) await import(path.join(addons, id, 'ui/build.mjs')).then(m => m.build()) } -// The add-ons the specs serve from their build output: Studio and Talk through -// installStudioAddons, Face and Fine-tuning through their own routes. -export async function buildStudioAddons(ids = ['studio', 'talk', 'face', 'fine-tuning']) { +// The add-ons the specs serve from their build output: Studio, Talk and Voice +// through installStudioAddons, Face and Fine-tuning through their own routes. +export async function buildStudioAddons(ids = ['studio', 'talk', 'voice', 'face', 'fine-tuning']) { await buildAddonBundles(ids) process.env[BUILT] = '1' } @@ -55,7 +55,7 @@ export function packagedApp(id, over = {}) { // Returns the state of mockAddons. export async function installStudioAddons(page, { ids = ['studio', 'talk'], ...options } = {}) { const dirs = await Promise.all(ids.map(build)) - await page.route(/\/api\/addons\/(studio|talk)\/assets\//, route => { + await page.route(/\/api\/addons\/(studio|talk|voice)\/assets\//, route => { const parts = new URL(route.request().url()).pathname.split('/') const id = parts[3] const file = parts.slice(6).join('/')